d2lang/d2 · error

failed to parse value %q: %w

Error message

failed to parse value %q: %w

What it means

ParseValue wraps the D2 parser error returned when a standalone string cannot be parsed as a D2 value. The parser collects errors into p.err; if any occurred during parseValue, the raw input is echoed with %q and the underlying ParseError is wrapped with %w so callers can inspect position details.

Source

Thrown at d2parser/parse.go:126

	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 {
		return nil, fmt.Errorf("empty value: %q", value)
	}
	return v.Unbox(), nil
}

// TODO: refactor parser to keep entire file in memory as []rune
//   - trivial to then convert positions
//   - lookahead is gone, just forward back as much as you want :)
//   - streaming parser isn't really helpful.
//   - just read into a string even and decode runes forward/back as needed
//   - the whole file essentially exists within the parser as the AST anyway...
//
// TODO: ast struct that combines map & errors and pass that around
type parser struct {
	path     string
	pos      d2ast.Position

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Print the wrapped ParseError (errors.Unwrap / %v) to get the line/column of the syntax fault
  2. Fix the D2 syntax in the input string (quotes, brackets, escaping)
  3. Validate the value with a small test parse in dev before runtime use

Example fix

// before
v, err := d2parser.ParseValue(`shape: circle: extra`) // syntax fault
// after
v, err := d2parser.ParseValue(`shape: circle`)
Defensive patterns

Strategy: try-catch

Validate before calling

if strings.TrimSpace(value) == "" {
    return fmt.Errorf("refusing to parse empty D2 value")
}
if !utf8.ValidString(value) {
    return fmt.Errorf("value must be valid UTF-8")
}

Type guard

func isParseError(err error) bool {
    var pe *d2parser.ParseError
    return errors.As(err, &pe)
}

Try / catch

v, err := d2parser.ParseValue(input)
if err != nil {
    var pe *d2parser.ParseError
    if errors.As(err, &pe) {
        return fmt.Errorf("D2 syntax error in %q: %v", input, pe)
    }
    return err
}

Prevention

When it happens

Trigger: Calling d2parser.ParseValue with a string that violates D2 value syntax — unbalanced quotes/brackets, invalid key-value structure, or tokens the D2 grammar rejects.

Common situations: Programmatically generating D2 snippets with bad quoting or escaping; feeding user-supplied labels/shapes into the parser; template strings containing D2-illegal characters.

Understand the failure class

Related errors


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