apache/shardingsphere · error · FirebirdProtocolException

Batch BLOB segment declares %d bytes, but only %d bytes rema

Error message

Batch BLOB segment declares %d bytes, but only %d bytes remain

What it means

Thrown while parsing a Firebird batch BLOB segments packet: a 2-byte little-endian length prefix declares N bytes of segment data, but fewer than N bytes remain in the buffer. The declared size and actual remaining size are included in the message. The packet is internally inconsistent, so the segment list cannot be deserialized.

Source

Thrown at database/protocol/dialect/firebird/src/main/java/org/apache/shardingsphere/database/protocol/firebird/packet/command/query/blob/FirebirdBatchBlobSegmentsCommandPacket.java:58

    
    private final Collection<byte[]> segments;
    
    public FirebirdBatchBlobSegmentsCommandPacket(final FirebirdPacketPayload payload) {
        payload.skipReserved(4);
        blobHandle = payload.readBlobHandle();
        segmentLength = payload.readInt4();
        segments = readSegments(payload.readBuffer());
    }
    
    private Collection<byte[]> readSegments(final ByteBuf buffer) {
        Collection<byte[]> result = new LinkedList<>();
        while (buffer.isReadable()) {
            if (buffer.readableBytes() < Short.BYTES) {
                throw new FirebirdProtocolException("Truncated batch BLOB segment length");
            }
            int segmentLength = buffer.readUnsignedShortLE();
            if (buffer.readableBytes() < segmentLength) {
                throw new FirebirdProtocolException("Batch BLOB segment declares %d bytes, but only %d bytes remain", segmentLength, buffer.readableBytes());
            }
            byte[] segmentData = new byte[segmentLength];
            buffer.readBytes(segmentData);
            result.add(segmentData);
        }
        return result;
    }
    
    @Override
    protected void write(final FirebirdPacketPayload payload) {
    }
    
    /**
     * Get length of packet.
     *
     * @param payload Firebird packet payload
     * @return length of packet
     */

View on GitHub (pinned to e952770a21)

Solutions

  1. Compare the declared length in the message with the actual remaining bytes to confirm corruption vs. truncation
  2. Fix the client/proxy that builds the batch so the 2-byte LE prefix exactly matches the segment payload size
  3. Check for intermediaries (proxies, TLS terminators) that clip or coalesce frames incorrectly
  4. Round-trip a known-good blob with the official Firebird driver and diff the bytes to locate the divergence
Defensive patterns

Strategy: try-catch

Try / catch

try {
    packet = new FirebirdBatchBlobSegmentsCommandPacket(payload);
} catch (FirebirdProtocolException ex) {
    // message already carries declared vs remaining bytes; fail the connection,
    // do not attempt partial reads — segment data would be attributed to the wrong segment
    abortConnection(ex);
}

Prevention

When it happens

Trigger: Constructing FirebirdBatchBlobSegmentsCommandPacket where readSegments() reads a segmentLength via readUnsignedShortLE() larger than buffer.readableBytes() — e.g. a length prefix of 5000 with only 300 bytes left.

Common situations: Client bugs that write a wrong length prefix, packet truncation in transit, or endianness mistakes (writing big-endian lengths against a little-endian protocol) producing huge declared sizes.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/ca25d589471b08b3. Report an issue: GitHub.