d2lang/d2 · error
received empty arrow head marker for: %#v
Error message
received empty arrow head marker for: %#v
What it means
When drawing a connection's SVG, if SrcArrow is not NoArrowhead, d2svg builds a start arrowhead marker; arrowheadMarker returns "" when the connection's arrowhead kind has no rendered definition. This is treated as an internal invariant violation and panics. It indicates a d2target.Arrowhead value the SVG renderer cannot translate into a marker.
Source
Thrown at d2renderers/d2svg/d2svg.go:1101
func drawConnection(writer io.Writer, diagramHash string, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape, sketch bool, inlineTheme *d2themes.Theme, markdown *markdownRenderer) (labelMask string, _ error) {
opacityStyle := ""
if connection.Opacity != 1.0 {
opacityStyle = fmt.Sprintf(" style='opacity:%f'", connection.Opacity)
}
classes := []string{base64.URLEncoding.EncodeToString([]byte(svg.EscapeText(connection.ID)))}
classes = append(classes, connection.Classes...)
classStr := fmt.Sprintf(` class="%s"`, strings.Join(classes, " "))
fmt.Fprintf(writer, `<g%s%s>`, classStr, opacityStyle)
var markerStart string
if connection.SrcArrow != d2target.NoArrowhead {
id := arrowheadMarkerID(diagramHash, false, connection)
if _, in := markers[id]; !in {
marker := arrowheadMarker(false, id, connection, inlineTheme)
if marker == "" {
panic(fmt.Sprintf("received empty arrow head marker for: %#v", connection))
}
fmt.Fprint(writer, marker)
markers[id] = struct{}{}
}
markerStart = fmt.Sprintf(`marker-start="url(#%s)" `, id)
}
var markerEnd string
if connection.DstArrow != d2target.NoArrowhead {
id := arrowheadMarkerID(diagramHash, true, connection)
if _, in := markers[id]; !in {
marker := arrowheadMarker(true, id, connection, inlineTheme)
if marker == "" {
panic(fmt.Sprintf("received empty arrow head marker for: %#v", connection))
}
fmt.Fprint(writer, marker)
markers[id] = struct{}{}
}View on GitHub (pinned to 0d69dca6f5)
Solutions
- Upgrade d2svg/d2target (and D2 generally) so renderer and diagram version match
- Inspect connection.SrcArrow for an unexpected value before rendering and normalize it to a supported kind
- Re-generate the diagram JSON/AST with the same D2 version used for rendering rather than hand-editing arrowhead values
- Patch arrowheadMarker to handle the new arrowhead kind if you added a custom one to d2target
Example fix
// before conn.SrcArrow = d2target.Arrowhead(99) // unknown // after conn.SrcArrow = d2target.ArrowArrowhead
Defensive patterns
Strategy: type-guard
Validate before calling
// Before Render, validate every connection's SrcArrow
for _, c := range diagram.Connections {
if !supportedArrowhead(c.SrcArrow) {
return fmt.Errorf("unsupported SrcArrow %d on connection %s", c.SrcArrow, c.ID)
}
} Type guard
func supportedArrowhead(a d2target.Arrowhead) bool {
switch a {
case d2target.NoArrowhead, d2target.ArrowArrowhead, d2target.TriangleArrowhead,
d2target.DiamondArrowhead, d2target.CircleArrowhead:
return true
}
return false
} Try / catch
// Go: recover the panic around Render
defer func() {
if r := recover(); r != nil {
if s, ok := r.(string); ok && strings.Contains(s, "empty arrow head marker") {
err = fmt.Errorf("render failed: %v", r)
} else { panic(r) }
}
}() Prevention
- Keep d2target and d2svg versions in lockstep (same module version)
- Never hand-edit serialized diagram JSON; regenerate with the same D2 version
- If adding arrowhead kinds to d2target, add matching cases to arrowheadMarker
- Fuzz/round-trip test all arrowhead combinations through Render
When it happens
Trigger: Calling Render (directly or via renderLegendConnectionIcon) on a diagram whose connection has a non-zero SrcArrow that arrowheadMarker(false, ...) cannot render — i.e. an unsupported/unknown arrowhead type, often from a newer or hand-built d2target AST.
Common situations: Version mismatch where a diagram serialized with a newer D2 arrowhead enum is rendered by an older d2svg; programmatic diagram construction setting SrcArrow to an unregistered kind; legend icons built with unusual arrowhead combinations.
Related errors
- invalid luminance category
- create OpenType face: %v
- code snippet style "github" not found
- code snippet formatter "svg" not found
- padding %d produces invalid SVG dimensions
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/7fa51d996d395e4f.
Report an issue: GitHub.