{"record":{"id":"0e9eb11bd0231b83","repo":"grpc-ecosystem/grpc-gateway","slug":"s-unexpected-token-v","errorCode":null,"errorMessage":"%s: unexpected token %v","messagePattern":"(.+?): unexpected token (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"openapiv3-merge/internal/merge/merge.go","lineNumber":197,"sourceCode":"\t\textras:     newOrderedObject(),\n\t}\n\tdec := json.NewDecoder(bytes.NewReader(in.Data))\n\tdec.UseNumber()\n\ttok, err := dec.Token()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s: %w\", in.Name, err)\n\t}\n\tif delim, ok := tok.(json.Delim); !ok || delim != '{' {\n\t\treturn nil, fmt.Errorf(\"%s: expected JSON object at top level\", in.Name)\n\t}\n\tfor dec.More() {\n\t\ttok, err := dec.Token()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%s: %w\", in.Name, err)\n\t\t}\n\t\tkey, ok := tok.(string)\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"%s: unexpected token %v\", in.Name, tok)\n\t\t}\n\t\tvar raw json.RawMessage\n\t\tif err := dec.Decode(&raw); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%s: %q: %w\", in.Name, key, err)\n\t\t}\n\t\tswitch key {\n\t\tcase \"openapi\":\n\t\t\tif err := json.Unmarshal(raw, &d.OpenAPI); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"%s: openapi: %w\", in.Name, err)\n\t\t\t}\n\t\tcase \"info\":\n\t\t\td.Info = raw\n\t\tcase \"servers\":\n\t\t\td.Servers = raw\n\t\tcase \"paths\":\n\t\t\tobj, err := decodeOrderedObject(raw)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"%s: paths: %w\", in.Name, err)","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/grpc-ecosystem/grpc-gateway/blob/a58a4436a376a4bcc7d8f10c4d4f919a8438bba9/openapiv3-merge/internal/merge/merge.go#L179-L215","documentation":"This error is returned when a token read as a top-level object key is not a JSON string (merge.go:195-197). In a well-formed JSON object every key is a string, so in practice this means the decoder's token stream got out of sync with expectations — the document is structurally invalid even if individual tokens parsed. The unexpected token's value is included in the message to aid debugging.","triggerScenarios":"Calling Merge with Input data whose object structure is malformed such that dec.Token() inside the key-reading loop yields a non-string token (e.g. a Delim like '}' or ':' appearing where a key is expected, due to mismatched braces, duplicate/stray delimiters, or hand-edited JSON).","commonSituations":"Hand-edited or machine-concatenated JSON with mismatched braces; a naive string-merge of two spec files; a converter that emitted invalid object structure; JSON with comments (JSONC/JSON5) confusing a prior preprocessor that only partially stripped them.","solutions":["Validate the file with a strict JSON parser (json.Valid, or jsonlint) — a non-string key token indicates structural corruption that validation will catch.","Remove JSONC/JSON5 comments and trailing commas before passing the data (convert to standard JSON first).","Do not concatenate spec files as text; merge them via Merge with separate Inputs instead.","If keys are generated programmatically, ensure they are always emitted as quoted JSON strings."],"exampleFix":"// before\ncombined := append(bytes.TrimSuffix(specA, []byte(\"}\")), '{', ...) // string-concat merge\n// after\nmerged, err := merge.Merge([]merge.Input{\n    {Name: \"a\", Data: specA},\n    {Name: \"b\", Data: specB},\n})","handlingStrategy":"validation","validationCode":"func strictJSONCheck(data []byte) error {\n    if !json.Valid(data) {\n        return errors.New(\"structurally invalid JSON: check braces, commas, and that all keys are quoted strings\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unexpected token\") {\n    return fmt.Errorf(\"spec is not a well-formed JSON object; validate with jsonlint: %w\", err)\n}","preventionTips":["Strip JSONC/JSON5 comments and trailing commas before merging.","Merge documents through Merge Inputs, never by concatenating file text.","Always emit generated keys as quoted JSON strings.","Add a lint step (jsonlint / json.Valid) to CI before running merge tooling."],"tags":["json","structure","parsing","go"],"backgroundTag":"invalid-json-structure","analyzedSha":"a58a4436a376a4bcc7d8f10c4d4f919a8438bba9","analyzedAt":"2026-09-02T10:28:31.537Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T16:17:10.729Z"}