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

  1. Re-generate the diagram with the same terrastruct/d2 version used for rendering
  2. Confirm the diagram JSON was not hand-edited or corrupted between compile and render
  3. Check for mismatched d2target versions between your go.mod and any vendored renderer
  4. 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

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


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/86a997a968dcb8d0. Report an issue: GitHub.