d2lang/d2 · error
failed to parse map key %q: %w
Error message
failed to parse map key %q: %w
What it means
ParseMapKey parses a string intended to be a map key with an optional inner map (e.g. 'x: {\n y\n}') into a d2ast.Key. If the parser records any diagnostics during parseMapKey, the error is wrapped with this message and %w, preserving the underlying ParseError.
Source
Thrown at d2parser/parse.go:110
k := p.parseKey()
if !p.err.Empty() {
return nil, fmt.Errorf("failed to parse key %q: %w", key, p.err)
}
if k == nil {
return nil, fmt.Errorf("empty key: %q", key)
}
return k, nil
}
func ParseMapKey(mapKey string) (*d2ast.Key, error) {
p := &parser{
reader: strings.NewReader(mapKey),
err: &ParseError{},
}
mk := p.parseMapKey()
if !p.err.Empty() {
return nil, fmt.Errorf("failed to parse map key %q: %w", mapKey, p.err)
}
if mk == nil {
return nil, fmt.Errorf("empty map key: %q", mapKey)
}
return mk, nil
}
func ParseValue(value string) (d2ast.Value, error) {
p := &parser{
reader: strings.NewReader(value),
err: &ParseError{},
}
v := p.parseValue()
if !p.err.Empty() {
return nil, fmt.Errorf("failed to parse value %q: %w", value, p.err)
}
if v.Unbox() == nil {View on GitHub (pinned to 0d69dca6f5)
Solutions
- Unwrap the error to see the exact parse position/token
- Ensure braces are balanced and the snippet is a valid key with optional map block
- Validate the snippet against d2fmt to normalize whitespace/newlines before parsing
- Build keys/maps with d2aster AST constructors rather than string templates
Example fix
// before
mk, err := d2parser.ParseMapKey("x: {") // unbalanced brace
// after
mk, err := d2parser.ParseMapKey("x: {\n y\n}") Defensive patterns
Strategy: try-catch
Validate before calling
func snippetIsBalanced(s string) bool {
open := strings.Count(s, "{")
close := strings.Count(s, "}")
return open == close && strings.TrimSpace(s) != ""
}
// if !snippetIsBalanced(snippet) { fix snippet before ParseMapKey } Try / catch
mk, err := d2parser.ParseMapKey(snippet)
if err != nil {
var parseErr *d2parser.ParseError
if u := errors.Unwrap(err); u != nil {
if pe, ok := u.(*d2parser.ParseError); ok {
parseErr = pe
}
}
return fmt.Errorf("bad map key snippet %q: %v", snippet, parseErr)
} Prevention
- Balance-check braces in generated snippets before parsing
- Pass snippets through d2fmt to normalize formatting first
- Only pass key(+map) text, never full boards or connections
- Use AST builders (d2aster) for programmatic construction
When it happens
Trigger: Calling d2parser.ParseMapKey with text whose map-key syntax is invalid: unbalanced braces, a value line where a key was expected, bad quoting, or trailing content that cannot form a key/map.
Common situations: Constructing map-key snippets dynamically for d2oracle edits; passing a full board fragment including connections where only a key is allowed; newline/indentation mistakes when templates generate the snippet.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/73ef21b81f76ca7b.
Report an issue: GitHub.