apache/pulsar · error · IllegalArgumentException
Outbuffer has not enough space available
Error message
Outbuffer has not enough space available
What it means
MessageCryptoBc.encrypt computes cipher.getOutputSize(payload.remaining()) (ciphertext + 16-byte GCM tag) and requires the caller-supplied outBuffer to have at least that many bytes remaining. This guards against a silent BufferOverflowException from cipher.doFinal(payload, outBuffer); when the destination ByteBuffer is too small it throws IllegalArgumentException instead.
Source
Thrown at pulsar-client-messagecrypto-bc/src/main/java/org/apache/pulsar/client/impl/crypto/MessageCryptoBc.java:513
}
// Create gcm param
// TODO: Replace random with counter and periodic refreshing based on timer/counter value
byte[] iv = new byte[IV_LEN];
secureRandom.nextBytes(iv);
GCMParameterSpec gcmParam = new GCMParameterSpec(tagLen, iv);
// Update message metadata with encryption param
msgMetadata.setEncryptionParam(iv);
try {
// Encrypt the data
Cipher cipher = getAesGcmCipher();
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, gcmParam);
int maxLength = cipher.getOutputSize(payload.remaining());
if (outBuffer.remaining() < maxLength) {
throw new IllegalArgumentException("Outbuffer has not enough space available");
}
int bytesStored = cipher.doFinal(payload, outBuffer);
outBuffer.flip();
outBuffer.limit(bytesStored);
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | ShortBufferException e) {
log.error().attr("logCtx", logCtx).exception(e).log("Failed to encrypt message");
throw new PulsarClientException.CryptoException(e.getMessage());
}
}
private SecretKeySpec tryDecryptDataKey(String keyName, byte[] encryptedDataKey, List<KeyValue> encKeyMeta,
CryptoKeyReader keyReader) {
Map<String, String> keyMeta = new HashMap<String, String>();
encKeyMeta.forEach(kv -> {
keyMeta.put(kv.getKey(), kv.getValue());
});View on GitHub (pinned to 820761864e)
Solutions
- Size the out buffer as payload size plus at least 16 bytes (GCM tag), e.g. ByteBuffer.allocate(payload.remaining() + 16)
- Call the cipher's getOutputSize(payloadLen) yourself before allocating and clear/compact the buffer before reuse
- If reusing buffers, ensure outBuffer.clear() is called so remaining() reflects full capacity
- Verify the payload passed is not unexpectedly larger than the buffer allocation (e.g. chunking configured off with large messages)
Example fix
// before ByteBuffer out = ByteBuffer.allocate(payload.remaining()); // misses GCM tag // after ByteBuffer out = ByteBuffer.allocate(payload.remaining() + 16); // 16-byte GCM tag headroom
Defensive patterns
Strategy: validation
Validate before calling
// Size the output buffer before calling encrypt
int outSize = payload.remaining() + 16; // payload + GCM tag
ByteBuffer outBuffer = ByteBuffer.allocate(outSize);
if (outBuffer.remaining() < outSize) {
throw new IllegalStateException("encrypt output buffer too small");
} Try / catch
try {
crypto.encrypt(encryptionKeyInfo, payload, outBuffer);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Outbuffer")) {
outBuffer = ByteBuffer.allocate(payload.remaining() + 16);
crypto.encrypt(encryptionKeyInfo, payload, outBuffer);
} else {
throw e;
}
} Prevention
- Always allocate encryption output as payload size + 16 bytes for the GCM tag
- Call buffer.clear() before reusing pooled ByteBuffers
- Compute cipher.getOutputSize(payloadLen) instead of guessing buffer sizes
- Add a unit test that encrypts max-size messages with production-sized buffers
When it happens
Trigger: Calling MessageCryptoBc.encrypt(encryptionKeyInfo, chunkMessageBuffer, outBuffer) with an outBuffer whose remaining() capacity is smaller than payload size + GCM tag overhead (16 bytes) + any cipher block padding overhead.
Common situations: Reusing a pooled/rotated buffer that was sized for a smaller payload; forgetting that the output includes the 16-byte authentication tag; a producer chunked-message buffer allocated once and reused across differently sized messages.
Related errors
- Target buffer size is too small
- Failed to decode private key
- Failed to decode public key
- The ${alg.name()} algorithm does not support Key Pairs.
- Illegal base64 character or Key file ${keyConfUrl} doesn't e
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/bf9ca2b1f42f4315.
Report an issue: GitHub.