{"record":{"id":"fb95281ce67194bc","repo":"apache/beam","slug":"null","errorCode":null,"errorMessage":"null","messagePattern":"null","errorType":"exception","errorClass":"ClosedChannelException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/azure/src/main/java/org/apache/beam/sdk/io/azure/blobstore/AzureReadableSeekableByteChannel.java","lineNumber":46,"sourceCode":"\nclass AzureReadableSeekableByteChannel implements SeekableByteChannel {\n\n  private final BlobInputStream inputStream;\n  private boolean closed;\n  private final Long contentLength;\n  private long position = 0;\n\n  public AzureReadableSeekableByteChannel(BlobClient blobClient) {\n    inputStream = blobClient.openInputStream();\n    contentLength = blobClient.getProperties().getBlobSize();\n    inputStream.mark(contentLength.intValue());\n    closed = false;\n  }\n\n  @Override\n  public int read(ByteBuffer dst) throws IOException {\n    if (closed) {\n      throw new ClosedChannelException();\n    }\n\n    int read = 0;\n    if (dst.hasArray()) {\n      // Stores up to dst.remaining() bytes into dst.array() starting at dst.position().\n      // But dst can have an offset with its backing array, hence the + dst.arrayOffset().\n      read = inputStream.read(dst.array(), dst.position() + dst.arrayOffset(), dst.remaining());\n    } else {\n      byte[] myarray = new byte[dst.remaining()];\n      read = inputStream.read(myarray, 0, myarray.length);\n      dst.put(myarray);\n    }\n\n    if (read > 0) {\n      dst.position(dst.position() + read);\n    }\n    return read;\n  }","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/azure/src/main/java/org/apache/beam/sdk/io/azure/blobstore/AzureReadableSeekableByteChannel.java#L28-L64","documentation":"AzureReadableSeekableByteChannel.read() throws ClosedChannelException when the channel has already been closed. The reported message is null because ClosedChannelException is constructed without a message. Any read attempt after close() (or use of a channel closed by an error path) fails this way.","triggerScenarios":"Calling channel.read(buffer) after channel.close() was invoked; continuing to read after a try-with-resources block has exited; closing in one thread while another thread still reads.","commonSituations":"Reusing a reader object outside the scope of the try-with-resources that created it; wrapping the channel in code that closes it eagerly (e.g. after count-limited reads); concurrent close in multi-threaded pipelines.","solutions":["Keep all read calls inside the try-with-resources scope that owns the channel.","Reopen the channel with FileSystems.open() if you need to read after closing.","Check !channel.isOpen() before reading, or restructure so each read pass uses a fresh channel.","Synchronize close/read across threads so reads never race a close."],"exampleFix":"// before\nReadableByteChannel ch = FileSystems.open(resourceId);\nch.close();\nch.read(buffer); // ClosedChannelException\n// after\ntry (ReadableByteChannel ch = FileSystems.open(resourceId)) {\n  ch.read(buffer);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"boolean readable(SeekableByteChannel ch) { return ch != null && ch.isOpen(); }","tryCatchPattern":"try (ReadableByteChannel ch = FileSystems.open(resourceId)) {\n  ch.read(buffer);\n} catch (ClosedChannelException e) {\n  // reopen and retry once\n  try (ReadableByteChannel ch2 = FileSystems.open(resourceId)) { ch2.read(buffer); }\n}","preventionTips":["Scope all channel use inside try-with-resources.","Never cache and reuse channels after close; reopen instead.","Synchronize close and read when channels are shared across threads."],"tags":["java","nio","closed-channel","azure","io"],"backgroundTag":"channel-closed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}