apache/beam · error · IllegalArgumentException
Forbidden IOException when reading from InputStream
Error message
Forbidden IOException when reading from InputStream
What it means
decodeFromSafeStream wraps the coder's decode call over an UnownedInputStream and treats any escaping IOException as a contract violation, rethrowing it as IllegalArgumentException with this message (CoderExceptions pass through). Decoding an in-memory stream should only fail with CoderException for malformed data, never with raw I/O errors.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/util/CoderUtils.java:145
if (stream.available() != 0) {
throw new CoderException(
stream.available() + " unexpected extra bytes after decoding " + result);
}
return result;
}
/**
* Decodes a value from the given {@code stream}, which should be a stream that never throws
* {@code IOException}, such as {@code ByteArrayInputStream} or {@link
* ExposedByteArrayInputStream}.
*/
private static <T> T decodeFromSafeStream(
Coder<T> coder, InputStream stream, Coder.Context context) throws CoderException {
try {
return coder.decode(new UnownedInputStream(stream), context);
} catch (IOException exn) {
Throwables.propagateIfPossible(exn, CoderException.class);
throw new IllegalArgumentException(
"Forbidden IOException when reading from InputStream", exn);
}
}
private static ByteArrayOutputStream getThreadLocalOutputStream() {
SoftReference<ExposedByteArrayOutputStream> refStream = threadLocalOutputStream.get();
ExposedByteArrayOutputStream stream = refStream == null ? null : refStream.get();
if (stream == null) {
stream = new ExposedByteArrayOutputStream();
threadLocalOutputStream.set(new SoftReference<>(stream));
}
stream.reset();
return stream;
}
/**
* Clones the given value by encoding and then decoding it with the specified Coder.
*View on GitHub (pinned to 12126d8942)
Solutions
- Examine the wrapped cause to find the underlying IOException source
- Fix the custom Coder so decode throws CoderException (or EOF-related exceptions the coder API allows) instead of raw IOException for data problems
- Validate input bytes (e.g. Base64 correctness) before calling decode
- Ensure the InputStream passed in is fully readable and not closed/broken
Example fix
// before
public T decode(InputStream in, Context ctx) throws IOException {
return mapper.readValue(new GZIPInputStream(in), T.class); // raw IOException
}
// after
public T decode(InputStream in, Context ctx) throws IOException, CoderException {
try {
return mapper.readValue(new GZIPInputStream(in), T.class);
} catch (IOException e) {
throw new CoderException("malformed encoded value", e);
}
} Defensive patterns
Strategy: try-catch
Try / catch
try {
T v = CoderUtils.decodeFromByteArray(coder, bytes);
} catch (IllegalArgumentException e) {
throw new CoderException("decode hit an I/O failure", e.getCause());
} Prevention
- Write custom decoders that throw CoderException, not raw IOException, for malformed data
- Pre-validate inputs (Base64, compression) before decode
- Ensure passed InputStreams are open and fully readable
- Keep decode implementations free of side I/O
When it happens
Trigger: A custom Coder's decode() throws IOException not derived from CoderException; decoding a Base64 input via decodeFromBase64 whose underlying source stream errors; wrapped stream in a failed/closed state.
Common situations: Custom coders that perform additional I/O in decode(); stream wrappers (GZIP etc.) that throw mid-read; corrupted input sources passed where a stable in-memory stream was expected.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- %s does not support non zero terminator values. Received str
- Forbidden IOException when writing to OutputStream
- unexpected extra bytes after decoding
- invalid length " + length
- cannot encode a null Byte
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/a5d36b0255d39bef.
Report an issue: GitHub.