d2lang/d2 · error

empty value: %q

Error message

empty value: %q

What it means

ParseValue returns this when the input parses without errors but the resulting value unboxes to nil, i.e. the string is empty or resolves to nothing. The library treats a nil value as invalid input for a value context.

Source

Thrown at d2parser/parse.go:129

	}
	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
	utf16Pos bool

	reader    io.RuneReader

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Check for empty/whitespace input before calling ParseValue
  2. Supply a default value when the source field is empty
  3. If emptiness is legitimate, handle it before parsing instead of relying on the error

Example fix

// before
v, _ := d2parser.ParseValue(cfg.Label) // panics-free but err="empty value"
// after
if strings.TrimSpace(cfg.Label) == "" {
    return errors.New("label is required")
}
v, err := d2parser.ParseValue(cfg.Label)
Defensive patterns

Strategy: validation

Validate before calling

if strings.TrimSpace(value) == "" {
    // skip parsing or substitute a default
    value = defaultLabel
}

Try / catch

v, err := d2parser.ParseValue(value)
if err != nil {
    if strings.Contains(err.Error(), "empty value") {
        return defaultFallback, nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling d2parser.ParseValue with "" or a string that parses to a nil/unboxed value (e.g. only whitespace or a construct producing no value).

Common situations: Building D2 documents from template/config data where a field is missing and an empty string is passed through unchecked.

Related errors


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