gohugoio/hugo · error
Error: Line did not parse to a valid JSON object\n
Error message
Error: Line did not parse to a valid JSON object\n
What it means
Printed by genwebp's parse_input_message (webp.c:339) when json_parse_string succeeded but the root JSON value is not a JSONObject. The worker frees the value and returns an empty InputMessage with no response. Same semantics as the genavif counterpart (821).
Source
Thrown at internal/warpc/genwebp/webp.c:339
config->method = opts.method;
return 1;
}
InputMessage parse_input_message(const char *line)
{
InputMessage msg = {0};
JSON_Value *root_value = json_parse_string(line);
if (root_value == NULL)
{
fprintf(stderr, "Error parsing JSON line\n");
return msg;
}
if (json_value_get_type(root_value) != JSONObject)
{
fprintf(stderr, "Error: Line did not parse to a valid JSON object\n");
json_value_free(root_value);
return msg;
}
JSON_Object *root_object = json_value_get_object(root_value);
JSON_Object *header_object = json_object_get_object(root_object, "header");
if (header_object != NULL)
{
msg.header.version = (int)json_object_get_number(header_object, "version");
msg.header.id = (int)json_object_get_number(header_object, "id");
const char *command_str = json_object_get_string(header_object, "command");
if (command_str != NULL)
{
strncpy(msg.header.command, command_str, sizeof(msg.header.command) - 1);
msg.header.command[sizeof(msg.header.command) - 1] = '\0';
}
const char *err_str = json_object_get_string(header_object, "err");View on GitHub (pinned to 52c9bd7908)
Solutions
- Send only a single JSON object per line with a `header` containing `command` and `id`.
- Validate the root token type on the Go side with json.Decoder before writing.
- Diff the envelope against parse_input_message and write_output_message schemas.
- Add a regression test asserting a non-object root is handled deterministically.
Example fix
// before
"decode"
// after
{"header":{"version":1,"id":42,"command":"decode"},"data":{"params":{}}} Defensive patterns
Strategy: validation
Validate before calling
func mustBeJSONObject(b []byte) error {
dec := json.NewDecoder(bytes.NewReader(b))
tok, err := dec.Token()
if err != nil { return err }
if d, ok := tok.(json.Delim); !ok || d != '{' {
return fmt.Errorf("command root is not a JSON object")
}
return nil
} Prevention
- Build commands as a struct or map[string]any so the root is always an object.
- Reject non-object roots at the host boundary.
- Document the envelope schema in the warpc package and test against it.
When it happens
Trigger: The host sends a JSON array, bare string/number, or any non-object root; or a framing bug concatenates objects so parson yields a non-object root.
Common situations: Hand-rolled test clients sending `[...]` instead of `{...}`, a protocol-version mismatch with a new batch format, leftover bytes from a prior command making the line start with a stray token, or a JSON producer emitting a top-level scalar under error.
Related errors
- Error: Line did not parse to a valid JSON object\n
- Error parsing JSON line\n
- Error parsing JSON line\n
- Error reading blob header\n
- [%d] Error reading blob data (size: %llu read: %zu) \n
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/0f820b05de2e34c0.
Report an issue: GitHub.