{"record":{"id":"a5d36b0255d39bef","repo":"apache/beam","slug":"forbidden-ioexception-when-reading-from-inputstream","errorCode":null,"errorMessage":"Forbidden IOException when reading from InputStream","messagePattern":"Forbidden IOException when reading from InputStream","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/util/CoderUtils.java","lineNumber":145,"sourceCode":"    if (stream.available() != 0) {\n      throw new CoderException(\n          stream.available() + \" unexpected extra bytes after decoding \" + result);\n    }\n    return result;\n  }\n\n  /**\n   * Decodes a value from the given {@code stream}, which should be a stream that never throws\n   * {@code IOException}, such as {@code ByteArrayInputStream} or {@link\n   * ExposedByteArrayInputStream}.\n   */\n  private static <T> T decodeFromSafeStream(\n      Coder<T> coder, InputStream stream, Coder.Context context) throws CoderException {\n    try {\n      return coder.decode(new UnownedInputStream(stream), context);\n    } catch (IOException exn) {\n      Throwables.propagateIfPossible(exn, CoderException.class);\n      throw new IllegalArgumentException(\n          \"Forbidden IOException when reading from InputStream\", exn);\n    }\n  }\n\n  private static ByteArrayOutputStream getThreadLocalOutputStream() {\n    SoftReference<ExposedByteArrayOutputStream> refStream = threadLocalOutputStream.get();\n    ExposedByteArrayOutputStream stream = refStream == null ? null : refStream.get();\n    if (stream == null) {\n      stream = new ExposedByteArrayOutputStream();\n      threadLocalOutputStream.set(new SoftReference<>(stream));\n    }\n    stream.reset();\n    return stream;\n  }\n\n  /**\n   * Clones the given value by encoding and then decoding it with the specified Coder.\n   *","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/util/CoderUtils.java#L127-L163","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\npublic T decode(InputStream in, Context ctx) throws IOException {\n  return mapper.readValue(new GZIPInputStream(in), T.class); // raw IOException\n}\n// after\npublic T decode(InputStream in, Context ctx) throws IOException, CoderException {\n  try {\n    return mapper.readValue(new GZIPInputStream(in), T.class);\n  } catch (IOException e) {\n    throw new CoderException(\"malformed encoded value\", e);\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  T v = CoderUtils.decodeFromByteArray(coder, bytes);\n} catch (IllegalArgumentException e) {\n  throw new CoderException(\"decode hit an I/O failure\", e.getCause());\n}","preventionTips":["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"],"tags":["java","io","coders","decoding"],"backgroundTag":"unexpected-io-error","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}