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

  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.