d2lang/d2 · error
unknown object of type %T
Error message
unknown object of type %T
What it means
When rendering a diagram to SVG, the renderer iterates over objects and switches on their concrete type to draw shape-specific elements. If an object in the diagram's Icons/appendix/legend path is neither a known shape nor connection type, it returns this error rather than silently skipping it.
Source
Thrown at d2renderers/d2svg/d2svg.go:2920
markdown := newMarkdownRenderer(diagram.FontFamily, diagram.MonoFontFamily, inlineTheme)
for _, obj := range allObjects {
if c, is := obj.(d2target.Connection); is {
labelMask, err := drawConnection(buf, isolatedDiagramHash, c, markers, idToShape, sketch, inlineTheme, markdown)
if err != nil {
return nil, err
}
if labelMask != "" {
labelMasks = append(labelMasks, labelMask)
}
} else if s, is := obj.(d2target.Shape); is {
labelMask, err := drawShape(buf, appendixItemBuf, diagramHash, s, sketch, inlineTheme, markdown)
if err != nil {
return nil, err
} else if labelMask != "" {
labelMasks = append(labelMasks, labelMask)
}
} else {
return nil, fmt.Errorf("unknown object of type %T", obj)
}
}
// add all appendix items afterwards so they are always on top
fmt.Fprint(buf, appendixItemBuf)
if diagram.Legend != nil && (len(diagram.Legend.Shapes) > 0 || len(diagram.Legend.Connections) > 0) {
legendBuf := &bytes.Buffer{}
err := RenderLegend(legendBuf, diagram, diagramHash, inlineTheme)
if err != nil {
return nil, err
}
fmt.Fprint(buf, legendBuf)
}
// Note: we always want this since we reference it on connections even if there end up being no masked labels
left, top, w, h := dimensions(diagram, pad, tl, br)
if diagram.Legend != nil && (len(diagram.Legend.Shapes) > 0 || len(diagram.Legend.Connections) > 0) {View on GitHub (pinned to 0d69dca6f5)
Solutions
- Re-generate the diagram with the same terrastruct/d2 version used for rendering
- Confirm the diagram JSON was not hand-edited or corrupted between compile and render
- Check for mismatched d2target versions between your go.mod and any vendored renderer
- If you control the objects, ensure every item is a *d2target.Shape or *d2target.Connection
Example fix
// before
obj := customStruct{} // injected into diagram.Objects
// after
obj := &d2target.Shape{} // only supported object types in diagram Defensive patterns
Strategy: type-guard
Type guard
func isKnownObject(obj interface{}) bool {
switch obj.(type) {
case *d2target.Shape, *d2target.Connection:
return true
}
return false
} Prevention
- Render with the same d2 version that compiled the diagram
- Never hand-edit serialized diagram JSON
- Round-trip diagram JSON through the same module version in CI
When it happens
Trigger: Rendering a d2target.Diagram whose internal objects slice contains an unexpected type — typically from deserializing a diagram JSON produced by a different d2 version, or hand-crafted/modified diagram JSON.
Common situations: Caching rendered diagram JSON across version upgrades; custom tools that post-process d2 output JSON and inject objects; using d2svg.Render directly with an exported diagram that has an unrecognized object.
Related errors
- code snippet style "github" not found
- code snippet formatter "svg" not found
- padding %d produces invalid SVG dimensions
- received empty arrow head marker for: %#v
- unknown svg path command "%s"
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/86a997a968dcb8d0.
Report an issue: GitHub.