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

  1. Unwrap the error to see the exact parse position/token
  2. Ensure braces are balanced and the snippet is a valid key with optional map block
  3. Validate the snippet against d2fmt to normalize whitespace/newlines before parsing
  4. 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

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

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/73ef21b81f76ca7b. Report an issue: GitHub.