alibaba/canal · error · CanalClientException
deserializer failed by ${e.getMessage()}
Error message
deserializer failed by ${e.getMessage()} What it means
This is the outer catch-all in CanalMessageSerializerUtil.deserializer: any Exception raised while parsing the Packet/Messages/Entry (including the inner unexpected-packet-type and ACK errors) is rewrapped as a CanalClientException with this prefix and the original cause chained. It surfaces as the single failure point for all malformed or unsupported canal message bytes.
Source
Thrown at connector/core/src/main/java/com/alibaba/otter/canal/connector/core/util/CanalMessageSerializerUtil.java:128
} else {
for (ByteString byteString : messages.getMessagesList()) {
result.addEntry(CanalEntry.Entry.parseFrom(byteString));
}
result.setRaw(false);
}
return result;
}
case ACK: {
CanalPacket.Ack ack = CanalPacket.Ack.parseFrom(p.getBody());
throw new CanalClientException("something goes wrong with reason: " + ack.getErrorMessage());
}
default: {
throw new CanalClientException("unexpected packet type: " + p.getType());
}
}
}
} catch (Exception e) {
throw new CanalClientException("deserializer failed by " + e.getMessage(), e);
}
}
}
View on GitHub (pinned to 87be50e876)
Solutions
- Read the chained cause (CanalClientException.getCause()) — it carries the real failure (InvalidProtocolBufferException, ACK error, unexpected type) and points to the precise fix.
- If the cause is InvalidProtocolBufferException, verify the byte[] was produced by CanalMessageSerializerUtil.serializer and was not truncated in transit.
- If the cause is the ACK error, inspect the upstream canal server / producer for the ack.getErrorMessage() reason.
- If flatMessage mode is enabled on the producer, parse the payload as JSON (JSON.parseObject(data, CommonMessage.class)) instead of calling the protobuf deserializer.
Example fix
// before
try {
Message msg = CanalMessageSerializerUtil.deserializer(data);
} catch (CanalClientException e) {
// only sees 'deserializer failed by ...'
}
// after — unwrap the real cause to diagnose
try {
Message msg = CanalMessageSerializerUtil.deserializer(data);
} catch (CanalClientException e) {
Throwable cause = e.getCause();
log.error("deserialize failed, rootCause={}, msg={}",
cause == null ? "unknown" : cause.getClass().getSimpleName(), e.getMessage());
throw e;
} Defensive patterns
Strategy: try-catch
Try / catch
try {
Message msg = CanalMessageSerializerUtil.deserializer(data);
} catch (CanalClientException e) {
Throwable root = e.getCause();
// branch on root: InvalidProtocolBufferException vs ACK vs unexpected-type
log.error("deserialize failed root={}", root == null ? "none" : root.getClass().getName(), e);
throw e;
} Prevention
- Always inspect getCause() — the 'deserializer failed by' prefix hides the real failure.
- For flatMessage producers, parse JSON instead of using the protobuf deserializer.
- Validate message integrity at the broker/consumer boundary before deserialization.
When it happens
Trigger: Any exception inside deserializer(): com.google.protobuf.InvalidProtocolBufferException from CanalPacket.Packet.parseFrom / Messages.parseFrom / Entry.parseFrom on truncated or non-protobuf data; the compression-not-supported CanalClientException; the unexpected-packet-type CanalClientException; or the ACK CanalClientException. All are caught at line 127 and rethrown with this message.
Common situations: Truncated message from the broker (network drop, partial serialization); bytes that are valid protobuf but not a CanalPacket; a flatMessage JSON payload mistakenly passed to the protobuf deserializer; partial write where only some of a multi-part message arrived.
Related errors
- unexpected packet type: ${p.getType()}
- Error when serializing message to byte[] by ${e.getMessage()
- compression is not supported in this connector
- ERROR ## parser of eromanga-event has an error , data:${entr
- unsupported version at this client.
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/a7322ed27503f630.
Report an issue: GitHub.