alibaba/canal · error · CanalClientException

deserializer failed by

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.

Solutions

  1. Read the chained cause (CanalClientException.getCause()) — it carries the real failure (InvalidProtocolBufferException, ACK error, unexpected type) and points to the precise fix.
  2. If the cause is InvalidProtocolBufferException, verify the byte[] was produced by CanalMessageSerializerUtil.serializer and was not truncated in transit.
  3. If the cause is the ACK error, inspect the upstream canal server / producer for the ack.getErrorMessage() reason.
  4. 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

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


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

Appendix: 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)