{"record":{"id":"7318ebacf1cedbfe","repo":"alibaba/canal","slug":"don-t-know-how-to-handle-column-type-d-meta-d","errorCode":null,"errorMessage":"!! Don't know how to handle column type=%d meta=%d (%04X)","messagePattern":"!! Don't know how to handle column type=(.+?) meta=(.+?) \\(%04X\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RowsLogBuffer.java","lineNumber":298,"sourceCode":"\r\n        if (type == LogEvent.MYSQL_TYPE_STRING) {\r\n            if (meta >= 256) {\r\n                int byte0 = meta >> 8;\r\n                int byte1 = meta & 0xff;\r\n                if ((byte0 & 0x30) != 0x30) {\r\n                    /* a long CHAR() field: see #37426 */\r\n                    len = byte1 | (((byte0 & 0x30) ^ 0x30) << 4);\r\n                    type = byte0 | 0x30;\r\n                } else {\r\n                    switch (byte0) {\r\n                        case LogEvent.MYSQL_TYPE_SET:\r\n                        case LogEvent.MYSQL_TYPE_ENUM:\r\n                        case LogEvent.MYSQL_TYPE_STRING:\r\n                            type = byte0;\r\n                            len = byte1;\r\n                            break;\r\n                        default:\r\n                            throw new IllegalArgumentException(String\r\n                                .format(\"!! Don't know how to handle column type=%d meta=%d (%04X)\", type, meta, meta));\r\n                    }\r\n                }\r\n            } else {\r\n                len = meta;\r\n            }\r\n        }\r\n\r\n        switch (type) {\r\n            case LogEvent.MYSQL_TYPE_LONG: {\r\n                // XXX: How to check signed / unsigned?\r\n                // value = unsigned ? Long.valueOf(buffer.getUint32()) :\r\n                // Integer.valueOf(buffer.getInt32());\r\n                value = valueOf(buffer.getInt32());\r\n                javaType = Types.INTEGER;\r\n                length = 4;\r\n                break;\r\n            }\r","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RowsLogBuffer.java#L280-L316","documentation":"Thrown by RowsLogBuffer.fetchValue when decoding a column declared MYSQL_TYPE_STRING whose metadata (meta) is >= 256. The code splits meta into byte0 (high) and byte1 (low); if byte0 has the 0x30 bits set (indicating a real STRING/ENUM/SET) but byte0 itself is none of MYSQL_TYPE_SET, MYSQL_TYPE_ENUM, or MYSQL_TYPE_STRING, the encoded type is unrecognized. This is a defensive guard for a STRING-type column whose real-type byte doesn't map to any known MySQL string family, as described in MySQL bug #37426.","triggerScenarios":"A Table_map_event advertises a column of type MYSQL_TYPE_STRING with a meta word whose high byte carries a type the switch doesn't enumerate. Produced by MySQL forks adding new string-like subtypes, or by binlog corruption altering the meta field.","commonSituations":"Replicating from a MySQL/MariaDB version newer than what Canal was built against; a corrupted Table_map event; a custom column type plugin on the master.","solutions":["Upgrade Canal to match the master's MySQL version so all real-type bytes are recognized.","Verify the column DDL on the master matches what Canal's table-map cache expects (re-snapshot if schema drifted).","If the column is genuinely new, add its type constant to the switch in RowsLogBuffer.fetchValue and map it to a sensible java.sql.Types.","Filter the offending table out of replication (canal.instance.filter.regex) until Canal supports it."],"exampleFix":"// before\ncase LogEvent.MYSQL_TYPE_SET:\ncase LogEvent.MYSQL_TYPE_ENUM:\ncase LogEvent.MYSQL_TYPE_STRING:\n    type = byte0;\n    len = byte1;\n    break;\ndefault:\n    throw new IllegalArgumentException(String.format(\"!! Don't know how to handle column type=%d meta=%d (%04X)\", type, meta, meta));\n// after: treat unknown real-type byte as plain STRING instead of aborting\ndefault:\n    logger.warn(\"Unknown STRING real-type byte {} (meta={}), treating as STRING\", byte0, meta);\n    type = LogEvent.MYSQL_TYPE_STRING;\n    len = byte1;","handlingStrategy":"validation","validationCode":"// Before relying on fetchValue, validate the column type/meta against a known-good schema\nboolean isKnownStringSubtype(int byte0) {\n    return byte0 == LogEvent.MYSQL_TYPE_SET\n        || byte0 == LogEvent.MYSQL_TYPE_ENUM\n        || byte0 == LogEvent.MYSQL_TYPE_STRING;\n}","typeGuard":null,"tryCatchPattern":"try {\n    buffer.fetchValue(name, index, type, meta, isBinary);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"!! Don't know how to handle column type\")) {\n        logger.error(\"Unsupported STRING column type={}/meta={} in table {}, skipping event\", type, meta, tableId);\n        // optionally skip or null the column value\n    } else throw e;\n}","preventionTips":["Keep Canal and master MySQL versions aligned so table-map type bytes are all recognized.","Avoid exotic STRING sub-types in replicated schemas or filter their tables.","Pin the source schema and re-snapshot Canal's table-map cache after DDL changes."],"tags":["binlog","rows-buffer","column-type","string","parsing"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}