{"record":{"id":"7fa51d996d395e4f","repo":"d2lang/d2","slug":"received-empty-arrow-head-marker-for-v","errorCode":null,"errorMessage":"received empty arrow head marker for: %#v","messagePattern":"received empty arrow head marker for: %#v","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2renderers/d2svg/d2svg.go","lineNumber":1101,"sourceCode":"\nfunc 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) {\n\topacityStyle := \"\"\n\tif connection.Opacity != 1.0 {\n\t\topacityStyle = fmt.Sprintf(\" style='opacity:%f'\", connection.Opacity)\n\t}\n\n\tclasses := []string{base64.URLEncoding.EncodeToString([]byte(svg.EscapeText(connection.ID)))}\n\tclasses = append(classes, connection.Classes...)\n\tclassStr := fmt.Sprintf(` class=\"%s\"`, strings.Join(classes, \" \"))\n\n\tfmt.Fprintf(writer, `<g%s%s>`, classStr, opacityStyle)\n\tvar markerStart string\n\tif connection.SrcArrow != d2target.NoArrowhead {\n\t\tid := arrowheadMarkerID(diagramHash, false, connection)\n\t\tif _, in := markers[id]; !in {\n\t\t\tmarker := arrowheadMarker(false, id, connection, inlineTheme)\n\t\t\tif marker == \"\" {\n\t\t\t\tpanic(fmt.Sprintf(\"received empty arrow head marker for: %#v\", connection))\n\t\t\t}\n\t\t\tfmt.Fprint(writer, marker)\n\t\t\tmarkers[id] = struct{}{}\n\t\t}\n\t\tmarkerStart = fmt.Sprintf(`marker-start=\"url(#%s)\" `, id)\n\t}\n\n\tvar markerEnd string\n\tif connection.DstArrow != d2target.NoArrowhead {\n\t\tid := arrowheadMarkerID(diagramHash, true, connection)\n\t\tif _, in := markers[id]; !in {\n\t\t\tmarker := arrowheadMarker(true, id, connection, inlineTheme)\n\t\t\tif marker == \"\" {\n\t\t\t\tpanic(fmt.Sprintf(\"received empty arrow head marker for: %#v\", connection))\n\t\t\t}\n\t\t\tfmt.Fprint(writer, marker)\n\t\t\tmarkers[id] = struct{}{}\n\t\t}","sourceCodeStart":1083,"sourceCodeEnd":1119,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2renderers/d2svg/d2svg.go#L1083-L1119","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconn.SrcArrow = d2target.Arrowhead(99) // unknown\n// after\nconn.SrcArrow = d2target.ArrowArrowhead","handlingStrategy":"type-guard","validationCode":"// Before Render, validate every connection's SrcArrow\nfor _, c := range diagram.Connections {\n    if !supportedArrowhead(c.SrcArrow) {\n        return fmt.Errorf(\"unsupported SrcArrow %d on connection %s\", c.SrcArrow, c.ID)\n    }\n}","typeGuard":"func supportedArrowhead(a d2target.Arrowhead) bool {\n    switch a {\n    case d2target.NoArrowhead, d2target.ArrowArrowhead, d2target.TriangleArrowhead,\n        d2target.DiamondArrowhead, d2target.CircleArrowhead:\n        return true\n    }\n    return false\n}","tryCatchPattern":"// Go: recover the panic around Render\ndefer func() {\n    if r := recover(); r != nil {\n        if s, ok := r.(string); ok && strings.Contains(s, \"empty arrow head marker\") {\n            err = fmt.Errorf(\"render failed: %v\", r)\n        } else { panic(r) }\n    }\n}()","preventionTips":["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"],"tags":["go","panic","svg","rendering","arrowhead","invariant-violation"],"backgroundTag":"unsupported-arrowhead-marker","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}