{"record":{"id":"a08e6a3b9aa1bc7a","repo":"tomnomnom/gron","slug":"invalid-json-layout","errorCode":null,"errorMessage":"invalid JSON layout","messagePattern":"invalid JSON layout","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"statements.go","lineNumber":269,"sourceCode":"\t\tok = (v == nil)\n\t\tif !ok {\n\t\t\tgoto out\n\t\t}\n\t\tt = typNull\n\t}\n\n\tnbuf, err = json.Marshal(v)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"JSON internal error\")\n\t}\n\tnstr = string(nbuf)\n\ts = append(s, token{nstr, t})\n\n\ts = append(s, token{\";\", typSemi})\n\nout:\n\tif !ok {\n\t\treturn nil, errors.New(\"invalid JSON layout\")\n\t}\n\treturn s, nil\n}\n\n// ungron turns statements into a proper datastructure\nfunc (ss statements) toInterface() (interface{}, error) {\n\n\t// Get all the individually parsed statements\n\tvar parsed []interface{}\n\tfor _, s := range ss {\n\t\tu, err := ungronTokens(s)\n\n\t\tswitch err.(type) {\n\t\tcase nil:\n\t\t\t// no problem :)\n\t\tcase errRecoverable:\n\t\t\tcontinue\n\t\tdefault:","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/tomnomnom/gron/blob/88a6234ea2d0c487090988182ad9a7cdf6def924/statements.go#L251-L287","documentation":"statementFromJSONSpec parses a line of JSON-formatted gron output back into a statement (the `--json` ungron path). If the JSON does not decompose into the expected layout — a valid JSON array whose elements form `key = value;` parts — the parser returns \"invalid JSON layout\".","triggerScenarios":"Feeding `gron --json` output that was truncated, re-serialized with different structure, or hand-written into `gron --json --ungron`; any line where the inner JSON spec array is missing required elements (bare key, '=', value, ';').","commonSituations":"Post-processing gron --json output with jq/sed and mangling the structure, or version drift where gron --json output format changed between releases and old cached output is piped into a newer ungron.","solutions":["Feed unmodified gron --json output directly back into `gron --json --ungron` without intermediate transformations","Validate each input line is a valid JSON array before passing it to statementFromJSONSpec","Regenerate the statements with the same gron version rather than reusing stored output"],"exampleFix":"// before\n// input line: [\"json\",\".\",\"a\"]  (missing '=', value, ';')\ns, err := statementFromJSONSpec(line) // invalid JSON layout\n\n// after\n// input line: [\"json\",\".\",\"a\",\"=\",null,\";\"]\ns, err := statementFromJSONSpec(line) // ok","handlingStrategy":"validation","validationCode":"var spec []interface{}\nif err := json.Unmarshal([]byte(line), &spec); err != nil {\n\t// not valid JSON spec input; reject before statementFromJSONSpec\n}\nif len(spec) < 6 { /* missing '=', value, ';' */ }","typeGuard":"func isJSONSpecLine(line string) bool {\n\tvar spec []interface{}\n\treturn json.Unmarshal([]byte(line), &spec) == nil && len(spec) >= 6\n}","tryCatchPattern":"s, err := statementFromJSONSpec(line)\nif err != nil {\n\tif strings.Contains(err.Error(), \"invalid JSON layout\") {\n\t\t// reject or reserialize the line\n\t}\n\treturn err\n}","preventionTips":["Pipe gron --json output unmodified back into ungron","Do not reshape spec arrays with jq/sed","Keep gron versions consistent between produce and consume steps"],"tags":["go","gron","json","parsing"],"backgroundTag":"invalid-json-response","analyzedSha":"88a6234ea2d0c487090988182ad9a7cdf6def924","analyzedAt":"2026-09-06T11:35:31.658Z","contentChangedAt":"2026-09-06T11:35:31.658Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}