Handling DWG Proxy Entities During Conversion
Proxy entities — ACAD_PROXY_ENTITY objects — are placeholders that AutoCAD writes for custom objects created by vertical products such as Civil 3D and Plant 3D, standing in for classes the reading application does not understand. During DWG-to-DXF conversion they either keep only a cached graphical snapshot or are dropped entirely, so ezdxf reports entity.dxftype() == "ACAD_PROXY_ENTITY" and cannot decode any parametric geometry beyond those cached graphics. The correct handling is detection, logging by handle, and mitigation at the source rather than pretending the proxy is real geometry. This page is part of the DWG Proprietary Limitations reference and assumes you already have a converted DXF to inspect.
How ezdxf Handles Proxy Entities
Autodesk vertical products define their own object classes — a Civil 3D corridor, a Plant 3D pipe, an alignment — through object enablers, runtime modules that teach AutoCAD how to draw and edit those objects. When a drawing containing such objects is opened by software that lacks the matching enabler, AutoCAD substitutes a proxy: an ACAD_PROXY_ENTITY that preserves the object’s handle and, optionally, a cached graphical representation captured at save time, but not the parametric definition. The custom object’s real geometry lives in code the reader does not have.
ezdxf is exactly such a reader. It never had the object enabler, so a proxy stays a proxy: entity.dxftype() returns "ACAD_PROXY_ENTITY", and there is no property that reconstructs the original corridor or pipe. At best, if the file was saved with cached proxy graphics, a downstream tool can recover a frozen visual snapshot of lines and arcs — an approximation with no editable topology and no attributes. Treating that snapshot as authoritative geometry is the central mistake this page exists to prevent. Because DWG is a closed format, this limitation compounds the general reasons ezdxf cannot read DWG directly, detailed in the pydwg Integration reference.
Proxy handling belongs to the same family of closed-format problems as version incompatibility; when a converted drawing is missing objects you expected, checking DWG version compatibility and scanning for proxies are the two first diagnostics to run.
Production-Ready Script
This script scans a converted DXF, classifies every entity as native or proxy, records the handle and any cached-graphics extent of each proxy, and emits a report of unrenderable objects that a pipeline can gate on.
# ezdxf>=1.1.0 | python>=3.9
import ezdxf
import json
import sys
from collections import Counter
from pathlib import Path
from typing import Any
PROXY_TYPES = {"ACAD_PROXY_ENTITY", "ACAD_PROXY_OBJECT", "PROXY_ENTITY"}
def proxy_extent(entity) -> dict[str, Any] | None:
"""
Try to read a cached bounding box for a proxy entity.
Proxy graphics, when present, let ezdxf compute an approximate extent.
Returns None when no cached graphics survived the conversion.
"""
try:
# bbox.extents works when cached proxy graphics are present.
from ezdxf import bbox
box = bbox.extents([entity])
if box.has_data:
return {
"min": [float(c) for c in box.extmin],
"max": [float(c) for c in box.extmax],
}
except Exception:
pass
return None
def scan_proxies(dxf_path: str, output_json: str) -> None:
try:
doc = ezdxf.readfile(dxf_path)
except (IOError, ezdxf.DXFStructureError) as exc:
sys.exit(f"Failed to load converted DXF: {exc}")
msp = doc.modelspace()
proxies: list[dict[str, Any]] = []
native_count = 0
type_histogram: Counter[str] = Counter()
for entity in msp:
dxftype = entity.dxftype()
type_histogram[dxftype] += 1
if dxftype in PROXY_TYPES:
extent = proxy_extent(entity)
proxies.append({
"handle": entity.dxf.handle,
"dxftype": dxftype,
"layer": entity.dxf.get("layer", "0"),
"cached_graphics": extent is not None,
"approx_extent": extent, # approximate only; never authoritative
})
else:
native_count += 1
total = native_count + len(proxies)
report = {
"source": dxf_path,
"total_entities": total,
"native_entities": native_count,
"proxy_entities": len(proxies),
"proxy_ratio": round(len(proxies) / total, 4) if total else 0.0,
"type_histogram": dict(type_histogram.most_common()),
"unrenderable": proxies,
}
Path(output_json).write_text(json.dumps(report, indent=2), encoding="utf-8")
print(
f"{len(proxies)} proxy / {native_count} native entities "
f"({report['proxy_ratio']:.1%} proxy) -> {output_json}"
)
# Gate: fail loudly if a meaningful fraction is unrenderable.
if report["proxy_ratio"] > 0.05:
print("WARNING: >5% of entities are proxies; re-export from source.")
if __name__ == "__main__":
scan_proxies("converted.dxf", "proxy_report.json")
Key implementation notes:
- Match on
entity.dxftype()against the proxy type names. Different AutoCAD releases and converters emitACAD_PROXY_ENTITY, and older files may surfacePROXY_ENTITY; check for the whole set. proxy_extent()returns an approximate bounding box only when cached proxy graphics survived conversion. ANoneextent means the object came through with no recoverable geometry — a total loss that must be reported, not silently skipped.- The
approx_extentfield is labelled approximate deliberately. Cached graphics are a save-time snapshot; never feed them into spatial indexing or measurement as if they were true geometry. - The
proxy_ratiogate turns a silent data-loss problem into a loud pipeline signal. A drawing that is 30% proxies is not usable geometry data regardless of how cleanly it converted. - The
type_histogramhelps triage which vertical product produced the file — a concentration of proxies on Civil 3D corridor layers points straight at the missing object enabler.
Compatibility Matrix
| Component | Supported range | Notes |
|---|---|---|
ezdxf |
>=1.1.0 |
dxftype(), dxf.handle, and ezdxf.bbox.extents are stable in 1.1.0+. |
| Python | 3.9+ |
Uses pathlib, collections.Counter, and typing. |
| DXF format | R2000 (AC1015) – R2018 (AC1032) |
Proxy entities are stored consistently across these revisions. |
| Proxy types | ACAD_PROXY_ENTITY, PROXY_ENTITY | Emitted for Civil 3D, Plant 3D, Map 3D custom objects. |
| Cached graphics | PROXYGRAPHICS=1 | Only recoverable when the source saved proxy graphics. |
| Object enablers | Source-side | The only path to true geometry is the originating application. |
Fallback Strategies
1. Re-export with PROXYGRAPHICS=1
The PROXYGRAPHICS system variable governs whether AutoCAD stores cached graphics for custom objects. If it was 0 at save time, proxies may carry no recoverable geometry after conversion. Ask the source team to set PROXYGRAPHICS=1 and re-save, which at least preserves a visual approximation you can log and, where acceptable, use for footprint extraction.
2. Explode custom objects at the source
The most reliable fix is to convert custom objects to plain AutoCAD primitives before export. In Civil 3D or Plant 3D, exploding corridors, alignments, or pipe runs to lines, arcs, and polylines produces native entities ezdxf decodes fully. This trades editability for portability — acceptable when the downstream consumer only needs geometry, not the parametric model.
3. Install the object enabler where the workflow allows
Autodesk publishes free object enablers for many verticals. In a workflow that still runs through an AutoCAD-family reader before the Python stage, installing the matching enabler lets the true geometry survive into the exported DXF. This does not help pure-ezdxf pipelines, which have no enabler mechanism, but it is worth flagging to the source team.
4. Request a native geometry export (IFC, DGN, or LandXML)
For infrastructure objects, a format built for the data often beats DXF entirely: LandXML for alignments and surfaces, IFC for building objects. Requesting a purpose-built export sidesteps the proxy problem, because the custom object is serialized as first-class geometry rather than an opaque proxy.
5. Treat cached graphics as approximate only
When you must use recovered cached graphics, quarantine them. Tag every derived feature as approximate, exclude it from measurement and clash analysis, and record the proxy handle so the provenance is auditable. Never let a proxy-derived footprint enter a dataset that downstream users assume is survey-grade.
FAQ
What is an ACAD_PROXY_ENTITY in a DWG file?
An ACAD_PROXY_ENTITY is a stand-in that AutoCAD writes for a custom object created by a vertical product such as Civil 3D or Plant 3D when the reading application lacks the object enabler that defines that class. It may carry a cached graphical representation but not the parametric geometry, so ezdxf cannot decode its true shape.
Can ezdxf recover geometry from a proxy entity?
No. ezdxf sees entity.dxftype() == "ACAD_PROXY_ENTITY" and can read only whatever cached proxy graphics were stored at save time. It cannot reconstruct the original custom object’s parametric geometry. Treat any recovered cached graphics as an approximate visual snapshot, not authoritative geometry.
What does PROXYGRAPHICS control?
The PROXYGRAPHICS system variable controls whether AutoCAD saves cached graphics for custom objects into the file. With PROXYGRAPHICS=1 the DWG stores a graphical snapshot that survives conversion; with PROXYGRAPHICS=0 proxies may carry no recoverable geometry at all after conversion.
How much proxy content is acceptable in a converted drawing?
There is no universal threshold, but a pipeline should gate on the proxy ratio. A drawing that is a few percent proxies on annotation layers may be usable; one that is tens of percent proxies on the layers carrying your target geometry is not, and should be sent back for a native re-export before any downstream processing.
Related Pages
- DWG Proprietary Limitations — parent reference on the closed-format constraints that make DWG hard to process in Python
- Understanding DWG Version Compatibility — sibling workflow on the release-dependent binary changes that also cause conversion loss
- pydwg Integration — related reference on reading proprietary
.dwgfiles and the conversion tooling around them - DXF Entity Structure Breakdown — how native entity types differ from opaque proxy objects at the group-code level