{"record":{"id":"06886e829bc9b65c","repo":"alibaba/canal","slug":"parsing-json-value","errorCode":null,"errorMessage":"parsing json value","messagePattern":"parsing json value","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonDiffConversion.java","lineNumber":134,"sourceCode":"            // Read path length\n            long path_length = buffer.getPackedLong();\n            // Print path\n            builder.append('\\'').append(buffer.getFixString((int) path_length)).append('\\'');\n\n            if (operation_int != DIFF_OPERATION_REMOVE) {\n                // Print comma between path and value\n                builder.append(\", \");\n                // Read value length\n                long value_length = buffer.getPackedLong();\n\n                Json_Value jsonValue = JsonConversion.parse_value(buffer.getUint8(),\n                    buffer,\n                    value_length - 1,\n                    charset);\n                buffer.forward((int) value_length - 1);\n                // Read value\n                if (jsonValue.m_type == Json_enum_type.ERROR) {\n                    throw new IllegalArgumentException(\"parsing json value\");\n                }\n                StringBuilder jsonBuilder = new StringBuilder();\n                jsonValue.toJsonString(jsonBuilder, charset);\n                builder.append(jsonBuilder);\n            }\n\n            // see https://github.com/alibaba/canal/pull/5018\n            if (buffer.position() - position >= len) {\n                builder.append(\")\");\n                break;\n            }\n\n            // Print closing parenthesis\n            if (!buffer.hasRemaining() || !Objects.equals(operation_names.get(diff_i + 1), operation_names.get(diff_i))) {\n                builder.append(\")\");\n            }\n\n            if (buffer.hasRemaining()) {","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/JsonDiffConversion.java#L116-L152","documentation":"Thrown during the second pass (print pass) of JSON diff parsing when the JSON value parsed from the diff payload has type Json_enum_type.ERROR. After calling JsonConversion.parse_value() on the value bytes within a REPLACE or INSERT operation, the result is checked for the ERROR sentinel type, indicating the value could not be parsed.","triggerScenarios":"In print_json_diff's second-pass while loop, for non-REMOVE operations, the code reads value_length, then calls JsonConversion.parse_value with the value's type byte. If parse_value returns a Json_Value with m_type == ERROR (which can happen if the internal parsing produced a sentinel rather than throwing), this exception fires.","commonSituations":"An embedded JSON value within the diff uses an unsupported type byte, the value_length - 1 parameter underflows (value_length is 0, making it -1 when cast to int), or the value data is corrupt/truncated. MySQL 8.0+ introducing new JSONB types not handled by parse_value.","solutions":["Check that value_length is > 1 before subtracting 1 to avoid underflow when cast to int.","Verify the JSONB type byte within the value portion is a recognized constant (0x0-0xC, 0xF).","Upgrade canal/dbsync to support the MySQL version producing the partial updates.","Hex-dump the value bytes within the diff entry to inspect the type byte."],"exampleFix":"// before\nlong value_length = buffer.getPackedLong();\nJson_Value jsonValue = JsonConversion.parse_value(buffer.getUint8(), buffer, value_length - 1, charset);\n\n// after: guard against underflow and ERROR\nlong value_length = buffer.getPackedLong();\nif (value_length < 1) {\n    logger.warn(\"Invalid value_length {} in JSON diff, skipping\", value_length);\n    return builder;\n}\nint valueType = buffer.getUint8();\nJson_Value jsonValue = JsonConversion.parse_value(valueType, buffer, value_length - 1, charset);\nif (jsonValue.m_type == Json_enum_type.ERROR) {\n    logger.warn(\"Failed to parse JSON diff value with type 0x{}\", Integer.toHexString(valueType));\n    return builder;\n}","handlingStrategy":"validation","validationCode":"// Pre-validate value_length before parse_value is called by the library\n// (this check must be done inside a fork or by wrapping the call)\n// At minimum, ensure value_length > 1 to prevent underflow in value_length - 1\nif (value_length < 1) {\n    logger.warn(\"JSON diff value_length underflow: {}\", value_length);\n    return;\n}","typeGuard":null,"tryCatchPattern":"try {\n    JsonDiffConversion.print_json_diff(buffer, len, columnName, columnIndex, charset);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"parsing json value\")) {\n        logger.warn(\"Embedded JSON value in diff could not be parsed, column={}\", columnName);\n    }\n    throw e;\n}","preventionTips":["Verify the embedded JSON type byte within the diff value is a recognized JSONB constant.","Ensure value_length is at least 2 (type byte + at least 1 data byte) to avoid underflow.","Upgrade canal/dbsync for MySQL 8.0 JSON format changes."],"tags":["json-diff","binlog","mysql","value-parsing","sentinel-type"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}