alibaba/canal · error · IllegalArgumentException

illegal json data

Error message

illegal json data

What it means

Thrown by JsonConversion.parse_array_or_object() when the supplied JSONB value length is smaller than twice the offset size (4 bytes for small, 8 for large). A MySQL binary JSON array/object must carry at least an element-count and a total-size entry; a value shorter than that cannot be valid, so the parser rejects it as illegal json data.

Source

Thrown at dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonConversion.java:82

        switch (type) {
            case JSONB_TYPE_SMALL_OBJECT:
                return parse_array_or_object(Json_enum_type.OBJECT, buffer, len, false, charset);
            case JSONB_TYPE_LARGE_OBJECT:
                return parse_array_or_object(Json_enum_type.OBJECT, buffer, len, true, charset);
            case JSONB_TYPE_SMALL_ARRAY:
                return parse_array_or_object(Json_enum_type.ARRAY, buffer, len, false, charset);
            case JSONB_TYPE_LARGE_ARRAY:
                return parse_array_or_object(Json_enum_type.ARRAY, buffer, len, true, charset);
            default:
                return parse_scalar(type, buffer, len, charset);
        }
    }

    private static Json_Value parse_array_or_object(Json_enum_type type, LogBuffer buffer, long len, boolean large,
                                                    Charset charset) {
        long offset_size = large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE;
        if (len < 2 * offset_size) {
            throw new IllegalArgumentException("illegal json data");
        }
        long element_count = read_offset_or_size(buffer, large);
        long bytes = read_offset_or_size(buffer, large);

        if (bytes > len) {
            throw new IllegalArgumentException("illegal json data");
        }
        long header_size = 2 * offset_size;
        if (type == Json_enum_type.OBJECT) {
            header_size += element_count * (large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL);
        }

        header_size += element_count * (large ? VALUE_ENTRY_SIZE_LARGE : VALUE_ENTRY_SIZE_SMALL);
        if (header_size > bytes) {
            throw new IllegalArgumentException("illegal json data");
        }
        return new Json_Value(type, buffer.rewind(), element_count, bytes, large);
    }

View on GitHub (pinned to 87be50e876)

Solutions

  1. Re-stream the binlog from a known-good position to rule out transient truncation.
  2. Verify the event is genuinely a JSON column (JSONB_TYPE_OBJECT/ARRAY marker) and not a misread type byte.
  3. Confirm the MySQL server version's binary JSON format matches what this JsonConversion supports.
  4. Validate the row event's column-count and length preamble upstream so parse_array_or_object receives correct bounds.
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check JSONB length before descending into parse_array_or_object
if (len < (large ? 8L : 4L)) {
    logger.warn("JSON value too short for header (len=" + len + ")");
    return null; // or throw a domain exception
}

Try / catch

try { Json_Value v = JsonConversion.parse_value(type, buf, len, charset); }
catch (IllegalArgumentException e) {
    if (e.getMessage().equals("illegal json data"))
        logger.warn("skipping malformed JSONB value in binlog", e);
}

Prevention

When it happens

Trigger: While decoding a binlog JSON column, the binary value passed to parse_array_or_object has len < 2*offset_size - either the length was misread from the event, the buffer was truncated, or the value is not actually JSON.

Common situations: Truncated/corrupt binlog row event; a length field read with the wrong endianness/size upstream; a MySQL version emitting a JSON binary format revision this parser does not recognize; partial event after a network drop.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/c349cec74a1049fb. Report an issue: GitHub.