apache/beam · error · IOError

Stream is closed.

Error message

Stream is closed.

What it means

_check_open() raises IOError('Stream is closed.') when any operation (tell, seek, read, readline, etc.) is attempted on a FilesystemIO stream whose closed flag is set. Once close() has been called the stream no longer fronts a valid downloader/reader, so every subsequent operation is rejected.

Solutions

  1. Reopen the file with FileSystems.open(path) before performing further operations.
  2. Track the closed state (f.closed) and guard read/tell calls, or keep the stream inside the `with` block that owns its lifetime.
  3. Remove duplicate close() calls so the stream isn't closed while still in use.
  4. Capture any data you need before the `with` block exits rather than deferring reads.

Example fix

// before
with FileSystems.open(path) as f:
    pass
pos = f.tell()  # IOError: Stream is closed.
// after
with FileSystems.open(path) as f:
    pos = f.tell()
    data = f.read()
Defensive patterns

Strategy: validation

Validate before calling

if f.closed:
    f = FileSystems.open(path)  # reopen before further ops

Type guard

def is_open(f) -> bool:
    return not getattr(f, 'closed', True)

Try / catch

try:
    pos = f.tell()
except IOError as e:
    if str(e) == 'Stream is closed.':
        f = FileSystems.open(path)
        pos = f.tell()
    else:
        raise

Prevention

When it happens

Trigger: Calling f.tell(), f.seek(...), or f.read(...) after f.close(); using a stream inside a `with` block after the block has exited; holding a reference to a stream whose underlying context manager closed it.

Common situations: Returning file-like objects from context managers and using them later; accidentally calling close() twice in cleanup code then reading again; iterator/generator code that outlives the `with FileSystems.open(...)` scope.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/b2a01fbcd2e230fa. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/io/filesystemio.py:305

    # Certain upload stream implementations seek to the end of a stream to check
    # length before completing an upload, so we support a no-op seek(0, SEEK_END).
    if whence == os.SEEK_END and offset == 0:
      return
    elif whence == os.SEEK_SET:
      if offset == self.position:
        return
      elif offset == self.last_block_position and self.last_block:
        self.position = offset
        self.remaining = b''.join([self.last_block, self.remaining])
        self.last_block = b''
        return
    raise NotImplementedError(
        'offset: %s, whence: %s, position: %s, last: %s' %
        (offset, whence, self.position, self.last_block_position))

  def _check_open(self):
    if self.closed:
      raise IOError('Stream is closed.')

View on GitHub (pinned to 12126d8942)