d2lang/d2 · error
cannot connect to reserved keyword
Error message
cannot connect to reserved keyword
What it means
Object.Connect in d2graph refuses to create an edge whose source or destination id segment is an unquoted d2 reserved keyword (like `shape`, `label`, `style`, etc.). Reserved keywords have special meaning in keys, so using one unquoted as an endpoint is ambiguous and rejected.
Source
Thrown at d2graph/d2graph.go:1327
}
commonIDA = append(commonIDA, srcIDA[0])
srcIDA = srcIDA[1:]
dstIDA = dstIDA[1:]
}
commonKey := ""
if len(commonIDA) > 0 {
commonKey = strings.Join(commonIDA, ".") + "."
}
return fmt.Sprintf("%s(%s %s %s)[%d]", commonKey, strings.Join(srcIDA, "."), e.ArrowString(), strings.Join(dstIDA, "."), e.Index)
}
func (obj *Object) Connect(srcID, dstID []d2ast.String, srcArrow, dstArrow bool, label string) (*Edge, error) {
for _, id := range [][]d2ast.String{srcID, dstID} {
for _, p := range id {
if _, ok := d2ast.ReservedKeywords[p.ScalarString()]; ok && p.IsUnquoted() {
return nil, errors.New("cannot connect to reserved keyword")
}
}
}
src := obj.ensureChildEdge(srcID)
dst := obj.ensureChildEdge(dstID)
e := &Edge{
Attributes: Attributes{
Label: Scalar{
Value: label,
},
},
Src: src,
SrcArrow: srcArrow,
Dst: dst,
DstArrow: dstArrow,
}View on GitHub (pinned to 0d69dca6f5)
Solutions
- Rename the node to a non-reserved identifier.
- If the name must stay, use a quoted string for that segment (d2ast String with IsUnquoted false) so it is treated literally.
- Check the identifier against d2ast.ReservedKeywords before calling Connect in generated code.
Example fix
// before connect(src: "label", dst: "a") // after connect(src: "'label'", dst: "a") // quoted, or rename the node
Defensive patterns
Strategy: validation
Validate before calling
for _, seg := range []string{srcName, dstName} {
if _, reserved := d2ast.ReservedKeywords[seg]; reserved { seg = "'" + seg + "'" }
} Type guard
func isReservedUnquoted(seg d2ast.String) bool {
_, ok := d2ast.ReservedKeywords[seg.ScalarString()]
return ok && seg.IsUnquoted()
} Try / catch
if _, err := obj.Connect(srcID, dstID, false, false, ""); err != nil && err.Error() == "cannot connect to reserved keyword" {
// quote the offending segments and retry
} Prevention
- Check endpoint names against d2ast.ReservedKeywords before connecting.
- Avoid naming nodes with d2 keywords like shape, label, style.
- Quote string identifiers programmatically when names come from user input.
When it happens
Trigger: Calling obj.Connect (directly or via d2oracle Set) where srcID or dstID contains an unquoted segment matching d2ast.ReservedKeywords, e.g. connecting to an object literally named `label` without quoting.
Common situations: Naming nodes after d2 keywords (`columns`, `rows`, `shape`, `label`) and then connecting them; programmatic graph building that doesn't quote identifiers.
Related errors
- expected "double-border" to be true or false
- spaces are not allowed in blockstring tags
- board names cannot contain dots or quotes
- cannot rename to reserved keyword: %#v
- expected "opacity" to be a number between 0.0 and 1.0
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/986906da471790d6.
Report an issue: GitHub.