{"record":{"id":"dff5e42deaf55d76","repo":"gohugoio/hugo","slug":"error-line-did-not-parse-to-a-valid-json-object-n","errorCode":null,"errorMessage":"Error: Line did not parse to a valid JSON object\\n","messagePattern":"Error: Line did not parse to a valid JSON object\\\\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/warpc/genavif/avif.c","lineNumber":92,"sourceCode":"\n} OutputMessage;\n\n#define MAX_LINE_LENGTH 4096\n\nInputMessage parse_input_message(const char *line)\n{\n    InputMessage msg = {0};\n\n    JSON_Value *root_value = json_parse_string(line);\n    if (root_value == NULL)\n    {\n        fprintf(stderr, \"Error parsing JSON line\\n\");\n        return msg;\n    }\n\n    if (json_value_get_type(root_value) != JSONObject)\n    {\n        fprintf(stderr, \"Error: Line did not parse to a valid JSON object\\n\");\n        json_value_free(root_value);\n        return msg;\n    }\n\n    JSON_Object *root_object = json_value_get_object(root_value);\n\n    JSON_Object *header_object = json_object_get_object(root_object, \"header\");\n    if (header_object != NULL)\n    {\n        msg.header.version = (int)json_object_get_number(header_object, \"version\");\n        msg.header.id = (int)json_object_get_number(header_object, \"id\");\n        const char *command_str = json_object_get_string(header_object, \"command\");\n        if (command_str != NULL)\n        {\n            strncpy(msg.header.command, command_str, sizeof(msg.header.command) - 1);\n            msg.header.command[sizeof(msg.header.command) - 1] = '\\0';\n        }\n        const char *err_str = json_object_get_string(header_object, \"err\");","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/internal/warpc/genavif/avif.c#L74-L110","documentation":"Printed by genavif's parse_input_message (avif.c:92) when json_parse_string succeeded but the top-level JSON value is not an object (e.g. a bare array, string, number, or true/false/null). The worker requires a JSON object so it can call json_object_get_object on it; anything else is treated as a malformed command, the root value is freed, and an empty InputMessage is returned with no output written.","triggerScenarios":"The host (or a test harness) sends a JSON array of commands, a bare number/string, or a JSON value whose root type is not JSONObject. Also occurs if a framing bug causes two JSON objects to be concatenated on one line and parson parses only the first token in a way that yields a non-object root.","commonSituations":"Hand-rolled test clients that send `[\"decode\"]` instead of `{\"header\":{...}}`; a protocol-version mismatch where the host uses a new array-based batch format; JSON producers that emit a top-level scalar under error conditions; or a previous command's leftover bytes making the line start with `]` or `,`.","solutions":["Ensure every command line is a single JSON object with at minimum a `header` object containing `command` and `id`.","Validate on the Go side before writing: parse the line once locally with encoding/json and reject if the root is not a json.Decoder token of type '{'.","Add a regression test in Hugo's warpc tests that asserts a non-object root produces a defined error path rather than silence.","Diff the message envelope against the schema documented in parse_input_message and write_output_message."],"exampleFix":"// before: caller sent a JSON array\n[{\"header\":{\"command\":\"decode\"}}]\n\n// after: a single JSON object per line\n{\"header\":{\"version\":1,\"id\":42,\"command\":\"decode\"},\"data\":{\"params\":{}}}","handlingStrategy":"validation","validationCode":"// Ensure the root JSON token is an object before sending.\nfunc mustBeJSONObject(b []byte) error {\n    dec := json.NewDecoder(bytes.NewReader(b))\n    tok, err := dec.Token()\n    if err != nil { return err }\n    if d, ok := tok.(json.Delim); !ok || d != '{' {\n        return fmt.Errorf(\"command root is not a JSON object\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Construct commands as map[string]any or a typed struct so the root is always an object.","Reject non-object roots at the host boundary before they reach the worker.","Document the envelope (header + data) explicitly in the warpc package."],"tags":["rpc","json","protocol","avif","validation"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}