d2lang/d2 · error
key does not exist
Error message
key does not exist
What it means
Rename checks that the key being renamed actually exists as a child of the board's root via HasChild; if not found, it returns "key does not exist". The rename is aborted because there is nothing to rename.
Source
Thrown at d2oracle/edit.go:1736
if len(mk.Edges) > 0 && mk.EdgeKey == nil {
// TODO: Not a fan of this dual interpretation depending on mk.Edges.
// Maybe we remove Rename and just have Move.
mk2, err := d2parser.ParseMapKey(newName)
if err != nil {
return nil, "", err
}
mk2.Key = mk.Key
mk = mk2
} else {
_, ok := d2ast.ReservedKeywords[newName]
if ok {
return nil, "", fmt.Errorf("cannot rename to reserved keyword: %#v", newName)
}
if mk.Key != nil {
obj, ok := boardG.Root.HasChild(d2graph.Key(mk.Key))
if !ok {
return nil, "", fmt.Errorf("key does not exist")
}
// If attempt to name something "x", but "x" already exists, rename it "x 2" instead
generatedName, _, err := generateUniqueKey(boardG, newName, obj, nil)
if err == nil {
newName = generatedName
}
}
// TODO: Handle mk.EdgeKey
mk.Key.Path[len(mk.Key.Path)-1] = d2ast.MakeValueBox(d2ast.RawString(newName, true)).StringBox()
}
g, err = move(g, boardPath, key, d2format.Format(mk), false)
return g, newName, err
}
func trimReservedSuffix(path []*d2ast.StringBox) []*d2ast.StringBox {
for i, p := range path {
if _, ok := d2ast.ReservedKeywords[p.Unbox().ScalarString()]; ok {View on GitHub (pinned to 0d69dca6f5)
Solutions
- Check g.Root.HasChild(d2graph.Key(parsedKey)) or equivalent before renaming.
- Correct the key string; remember d2 keys are case-sensitive.
- Recompile the graph so it reflects the current object set.
- Target the board where the object is actually defined via boardPath.
Example fix
// before
d2oracle.Rename(g, nil, "server.old", "server.new") // server.old gone
// after
if _, ok := g.Root.HasChild([]string{"server","old"}); ok {
d2oracle.Rename(g, nil, "server.old", "server.new")
} Defensive patterns
Strategy: validation
Validate before calling
import ("oss.terrastruct.com/d2/d2graph"; "oss.terrastruct.com/d2/d2parser")
mk, _ := d2parser.ParseMapKey(key)
if _, ok := g.Root.HasChild(d2graph.Key(mk)); !ok {
return fmt.Errorf("cannot rename: %q does not exist", key)
} Type guard
func keyExists(g *d2graph.Graph, key string) bool {
mk, err := d2parser.ParseMapKey(key)
if err != nil { return false }
_, ok := g.Root.HasChild(d2graph.Key(mk))
return ok
} Try / catch
ng, _, err := d2oracle.Rename(g, boardPath, key, newName)
if err != nil && strings.Contains(err.Error(), "key does not exist") {
return fmt.Errorf("object %q no longer exists; refresh diagram", key)
} Prevention
- Verify the key exists on the target board before renaming.
- Remember keys are case-sensitive.
- Refresh editor state after any prior delete/rename.
- Confirm the object is not glob/import generated before literal renames.
When it happens
Trigger: d2oracle.Rename(g, boardPath, key, newName) where key (parsed via d2parser) does not match an existing object path on the target board: typo, object already deleted, or key living on a different board than boardPath.
Common situations: Stale editor state where the object was removed by a previous operation; renaming an object defined via glob/import not addressable by this literal key; case mismatches in key.
Related errors
- cannot rename edge to node
- cannot rename edge to edge chain
- cannot rename to reserved keyword: %#v
- expected "shadow" to be true or false
- expected "3d" to be true or false
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/029dc21bda876813.
Report an issue: GitHub.