gohugoio/hugo · error

Error parsing JSON line\n

Error message

Error parsing JSON line\n

What it means

Printed by genwebp's parse_input_message (webp.c:333) when json_parse_string returns NULL for a stdin line. Identical semantics to the genavif counterpart (820): the line was not valid JSON, parson built no value tree, the function returns an empty InputMessage, and no response is written. The genwebp worker reads one JSON command line per iteration followed by a 16-byte blob header and blob payload.

Source

Thrown at internal/warpc/genwebp/webp.c:333

        {
            return 1;
        }
    }

    config->use_sharp_yuv = opts.useSharpYuv ? 1 : 0;
    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");

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Correlate with the previous stderr lines: this is usually downstream of an earlier framing error.
  2. Verify the host writes one JSON object terminated by '\n' followed by exactly 16 header bytes plus the declared payload.
  3. Keep command JSON under 4096 bytes; large frameDurations arrays can exceed MAX_LINE_LENGTH.
  4. Capture fd 0 bytes with strace to see the exact malformed line.
  5. Ensure no other writer touches genwebp's stdin.

Example fix

// before (host): no newline, two commands concatenated
w.Write([]byte(`{"header":{"command":"config"}}`))
w.Write([]byte(`{"header":{"command":"decode"}}`))

// after: newline-terminated, one per write
w.Write([]byte("{\"header\":{\"command\":\"config\"}}\n"))
// then send blob; then next command
Defensive patterns

Strategy: validation

Validate before calling

func writeWebpCommand(w io.Writer, cmd map[string]any) error {
    b, err := json.Marshal(cmd)
    if err != nil { return err }
    if len(b) > 4096 { return fmt.Errorf("command JSON %d bytes exceeds 4096", len(b)) }
    line := append(b, '\n')
    n, err := w.Write(line)
    if err != nil || n != len(line) { return errShortWrite }
    return nil
}

Prevention

When it happens

Trigger: A non-JSON byte sequence on genwebp's stdin: a prior blob-size mismatch causing binary bytes to be read as a command line, a line longer than MAX_LINE_LENGTH (4096) split by fgets, a debug writer accidentally attached to the RPC pipe, or a hand-crafted test sending plain text.

Common situations: Stream desynchronization after a previous short/long blob read, mismatched genwebp binary speaking a different envelope than the host, broken pipe / killed host mid-send, or test fixtures missing the trailing newline.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/1a98834044f9950a. Report an issue: GitHub.