{"record":{"id":"af8f8274c033a1c0","repo":"d2lang/d2","slug":"failed-to-parse-value-q-w","errorCode":null,"errorMessage":"failed to parse value %q: %w","messagePattern":"failed to parse value %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"d2parser/parse.go","lineNumber":126,"sourceCode":"\tmk := p.parseMapKey()\n\tif !p.err.Empty() {\n\t\treturn nil, fmt.Errorf(\"failed to parse map key %q: %w\", mapKey, p.err)\n\t}\n\tif mk == nil {\n\t\treturn nil, fmt.Errorf(\"empty map key: %q\", mapKey)\n\t}\n\treturn mk, nil\n}\n\nfunc ParseValue(value string) (d2ast.Value, error) {\n\tp := &parser{\n\t\treader: strings.NewReader(value),\n\t\terr:    &ParseError{},\n\t}\n\n\tv := p.parseValue()\n\tif !p.err.Empty() {\n\t\treturn nil, fmt.Errorf(\"failed to parse value %q: %w\", value, p.err)\n\t}\n\tif v.Unbox() == nil {\n\t\treturn nil, fmt.Errorf(\"empty value: %q\", value)\n\t}\n\treturn v.Unbox(), nil\n}\n\n// TODO: refactor parser to keep entire file in memory as []rune\n//   - trivial to then convert positions\n//   - lookahead is gone, just forward back as much as you want :)\n//   - streaming parser isn't really helpful.\n//   - just read into a string even and decode runes forward/back as needed\n//   - the whole file essentially exists within the parser as the AST anyway...\n//\n// TODO: ast struct that combines map & errors and pass that around\ntype parser struct {\n\tpath     string\n\tpos      d2ast.Position","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/d2parser/parse.go#L108-L144","documentation":"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.","triggerScenarios":"Calling d2parser.ParseValue with a string that violates D2 value syntax — unbalanced quotes/brackets, invalid key-value structure, or tokens the D2 grammar rejects.","commonSituations":"Programmatically generating D2 snippets with bad quoting or escaping; feeding user-supplied labels/shapes into the parser; template strings containing D2-illegal characters.","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"],"exampleFix":"// before\nv, err := d2parser.ParseValue(`shape: circle: extra`) // syntax fault\n// after\nv, err := d2parser.ParseValue(`shape: circle`)","handlingStrategy":"try-catch","validationCode":"if strings.TrimSpace(value) == \"\" {\n    return fmt.Errorf(\"refusing to parse empty D2 value\")\n}\nif !utf8.ValidString(value) {\n    return fmt.Errorf(\"value must be valid UTF-8\")\n}","typeGuard":"func isParseError(err error) bool {\n    var pe *d2parser.ParseError\n    return errors.As(err, &pe)\n}","tryCatchPattern":"v, err := d2parser.ParseValue(input)\nif err != nil {\n    var pe *d2parser.ParseError\n    if errors.As(err, &pe) {\n        return fmt.Errorf(\"D2 syntax error in %q: %v\", input, pe)\n    }\n    return err\n}","preventionTips":["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"],"tags":["d2","parser","syntax"],"backgroundTag":"d2-parse-syntax-error","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}