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
- Re-stream the binlog from a known-good position to rule out transient truncation.
- Verify the event is genuinely a JSON column (JSONB_TYPE_OBJECT/ARRAY marker) and not a misread type byte.
- Confirm the MySQL server version's binary JSON format matches what this JsonConversion supports.
- 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
- Validate event/length preamble before parsing JSON.
- Re-stream from a known-good binlog position on JSONB parse failures.
- Confirm MySQL server version JSONB compatibility.
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
- Unexpected response {} while fetching binlog: packet #{}, le
- Unexpected response {} while fetching binlog: packet #{}, le
- Invalid charset id: {}
- No such method: '{}' @ {}
- No such field: '{}' @ {}
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/c349cec74a1049fb.
Report an issue: GitHub.