{"record":{"id":"430c701010734bb1","repo":"tomnomnom/gron","slug":"failed-to-form-statements-s","errorCode":null,"errorMessage":"failed to form statements: %s","messagePattern":"failed to form statements: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"main.go","lineNumber":239,"sourceCode":"\t// Go's maps do not have well-defined ordering, but we want a consistent\n\t// output for a given input, so we must sort the statements\n\tif opts&optNoSort == 0 {\n\t\tsort.Sort(ss)\n\t}\n\n\tfor _, s := range ss {\n\t\tif opts&optJSON > 0 {\n\t\t\ts, err = s.jsonify()\n\t\t\tif err != nil {\n\t\t\t\tgoto out\n\t\t\t}\n\t\t}\n\t\tfmt.Fprintln(w, conv(s))\n\t}\n\nout:\n\tif err != nil {\n\t\treturn exitFormStatements, fmt.Errorf(\"failed to form statements: %s\", err)\n\t}\n\treturn exitOK, nil\n}\n\n// gronStream is like the gron action, but it treats the input as one\n// JSON object per line. There's a bit of code duplication from the\n// gron action, but it'd be fairly messy to combine the two actions\nfunc gronStream(r io.Reader, w io.Writer, opts int) (int, error) {\n\tvar err error\n\terrstr := \"failed to form statements\"\n\tvar i int\n\tvar sc *bufio.Scanner\n\tvar buf []byte\n\n\tvar conv func(s statement) string\n\tif opts&optMonochrome > 0 {\n\t\tconv = statementToString\n\t} else {","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/tomnomnom/gron/blob/88a6234ea2d0c487090988182ad9a7cdf6def924/main.go#L221-L257","documentation":"The gron action (JSON in, assignment statements out) wraps any failure from statementsFromJSON or jsonify into \"failed to form statements: %s\" with exit code exitFormStatements. The underlying cause (invalid JSON input, or a jsonify failure) is appended to the message.","triggerScenarios":"`gron` receiving stdin/files that are not valid JSON; `gron --json` where jsonify fails on a malformed statement; any statementsFromJSON error such as invalid top-level JSON.","commonSituations":"Piping empty input, HTML error pages, YAML, or truncated JSON into gron; curling an endpoint that returned a non-200 body; feeding multiple concatenated JSON documents without --stream/-s.","solutions":["Validate the input is a single well-formed JSON document (jq . < input) before piping to gron","Use `gron --stream` (or gronStream semantics) for multiple JSON objects per line/concatenated input","Check that the producing command (curl etc.) actually returned JSON and not an error page","Inspect the appended cause text in the message to identify the real failure"],"exampleFix":"// before\n$ curl -s api | gron        // api returned HTML -> failed to form statements: invalid character '<'\n\n// after\n$ curl -sfH 'Accept: application/json' api | jq -e . >/dev/null && curl -sfH 'Accept: application/json' api | gron","handlingStrategy":"validation","validationCode":"// validate JSON before piping to gron\nif err := json.NewDecoder(input).Decode(&v); err != nil {\n\t// invalid JSON; don't call gron\n}","typeGuard":"func isJSON(input io.Reader) bool {\n\tvar v interface{}\n\tdec := json.NewDecoder(input)\n\treturn dec.Decode(&v) == nil\n}","tryCatchPattern":"code, err := gron(input, output, opts)\nif err != nil {\n\tif strings.HasPrefix(err.Error(), \"failed to form statements:\") {\n\t\t// log cause, check input validity\n\t}\n\treturn err\n}","preventionTips":["Run `jq -e .` on input before gron to prove it's valid JSON","Use gron -s for multiple/concatenated JSON documents","Verify upstream HTTP calls returned JSON with -f / status checks"],"tags":["go","gron","cli","json","input-validation"],"backgroundTag":"json-parse-error","analyzedSha":"88a6234ea2d0c487090988182ad9a7cdf6def924","analyzedAt":"2026-09-06T11:35:31.658Z","contentChangedAt":"2026-09-06T11:35:31.658Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}