apache/pulsar · error · IllegalArgumentException

Target buffer size is too small

Error message

Target buffer size is too small

What it means

MessageCryptoBc.decryptData computes cipher.getOutputSize(payload.remaining()) for AES-GCM decryption and requires the caller-provided targetBuffer to have that much remaining space; otherwise it throws IllegalArgumentException before attempting the doFinal. The plaintext is generally smaller than the ciphertext but the library reserves worst-case output size.

Source

Thrown at pulsar-client-messagecrypto-bc/src/main/java/org/apache/pulsar/client/impl/crypto/MessageCryptoBc.java:596

        }
    }

    private boolean decryptData(SecretKey dataKeySecret, MessageMetadata msgMetadata,
                                ByteBuffer payload, ByteBuffer targetBuffer) {
        // unpack iv and encrypted data
        byte[] iv = msgMetadata.getEncryptionParam();

        GCMParameterSpec gcmParams = new GCMParameterSpec(tagLen, iv);
        try {
            // mark the buffers to allow resetting them in case of decryption failure
            payload.mark();
            targetBuffer.mark();

            Cipher cipher = getAesGcmCipher();
            cipher.init(Cipher.DECRYPT_MODE, dataKeySecret, gcmParams);
            int maxLength = cipher.getOutputSize(payload.remaining());
            if (targetBuffer.remaining() < maxLength) {
                throw new IllegalArgumentException("Target buffer size is too small");
            }
            int decryptedSize = cipher.doFinal(payload, targetBuffer);
            targetBuffer.flip();
            targetBuffer.limit(decryptedSize);
            return true;
        } catch (Exception e) {
            // reset the buffers so that decryption can be retried with the same buffers
            payload.reset();
            targetBuffer.reset();

            log.error().attr("logCtx", logCtx).exceptionMessage(e)
                    .log("Failed to decrypt message");
            return false;
        }
    }

    @Override
    public int getMaxOutputSize(int inputLen) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Allocate the target buffer with headroom equal to or greater than cipher.getOutputSize(encryptedLength) (i.e. at least the ciphertext size plus tag)
  2. Clear/flip the target buffer before reuse so remaining() is maximal
  3. If you control the call site, mirror the encrypt-side sizing logic (payload + 16-byte GCM tag)
  4. Check that chunked-message reassembly is passing the correct per-chunk buffer rather than a fixed undersized one

Example fix

// before
ByteBuffer target = ByteBuffer.allocate(encryptedChunk.remaining());
// after
ByteBuffer target = ByteBuffer.allocate(encryptedChunk.remaining() + 16); // worst-case GCM output
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the decrypt target buffer can hold worst-case output
int needed = cipher.getOutputSize(encryptedChunk.remaining()); // at least encrypted size + tag
if (targetBuffer.remaining() < needed) {
    targetBuffer = ByteBuffer.allocate(needed);
}

Try / catch

try {
    boolean ok = crypto.decrypt(dataKeyInfo, encryptedPayload, targetBuffer);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("Target buffer")) {
        // reallocate with headroom and retry once
        targetBuffer = ByteBuffer.allocate(encryptedPayload.remaining() + 16);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling MessageCryptoBc.decrypt where the targetBuffer (the output buffer holding the decrypted payload) has remaining() fewer bytes than cipher.getOutputSize(payload.remaining()) for the encrypted chunk being decrypted.

Common situations: Consumer allocating a receive buffer exactly equal to the ciphertext length; reusing a buffer across messages where a later message's encrypted chunk is larger; custom decryption flows that pass undersized buffers instead of using the library's default handling.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/67edc1ee98949a2b. Report an issue: GitHub.