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.PositionView on GitHub (pinned to 0d69dca6f5)
Solutions
- Print the wrapped ParseError (errors.Unwrap / %v) to get the line/column of the syntax fault
- Fix the D2 syntax in the input string (quotes, brackets, escaping)
- 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
- Validate D2 snippets with tests before shipping generated documents
- Escape quotes and special characters when interpolating user data into D2
- Reject empty strings at the config boundary before parsing
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- parent "_" can only be used in the beginning of paths, e.g.
- invalid use of parent "_"
- failed to parse key %q: %w
- empty key: %q
- failed to parse map key %q: %w
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/af8f8274c033a1c0.
Report an issue: GitHub.