{"record":{"id":"dc142c17f6c84dc8","repo":"apache/beam","slug":"output-stream-must-be-writable","errorCode":null,"errorMessage":"Output stream must be writable","messagePattern":"Output stream must be writable","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/gcp/bigquery_tools.py","lineNumber":1471,"sourceCode":"    return json.loads(encoded_table_row.decode('utf-8'))\n\n  def to_type_hint(self):\n    return Any\n\n\nclass JsonRowWriter(io.IOBase):\n  \"\"\"\n  A writer which provides an IOBase-like interface for writing table rows\n  (represented as dicts) as newline-delimited JSON strings.\n  \"\"\"\n  def __init__(self, file_handle):\n    \"\"\"Initialize an JsonRowWriter.\n\n    Args:\n      file_handle (io.IOBase): Output stream to write to.\n    \"\"\"\n    if not file_handle.writable():\n      raise ValueError(\"Output stream must be writable\")\n\n    self._file_handle = file_handle\n    self._coder = RowAsDictJsonCoder()\n\n  def close(self):\n    self._file_handle.close()\n\n  @property\n  def closed(self):\n    return self._file_handle.closed\n\n  def flush(self):\n    self._file_handle.flush()\n\n  def read(self, size=-1):\n    raise io.UnsupportedOperation(\"JsonRowWriter is not readable\")\n\n  def tell(self):","sourceCodeStart":1453,"sourceCodeEnd":1489,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/gcp/bigquery_tools.py#L1453-L1489","documentation":"Raised by `JsonRowWriter.__init__` when the provided file_handle is not writable (file_handle.writable() is False). The writer needs an output stream it can write JSON rows to, so it fails immediately at construction rather than later on write. This guards against read-only handles or write-mode mistakes.","triggerScenarios":"Constructing JsonRowWriter with a handle opened in read mode ('rb'/'r'), an io.BytesIO opened read-only, a closed stream, or a wrapper object whose writable() returns False.","commonSituations":"Copy-paste switching a reader to a writer without flipping the file mode; programmatically created buffers for testing opened without write flags; passing sys.stdin-like streams; passing an already-closed handle.","solutions":["Open the file/buffer in write mode: open(path, 'wb') or io.BytesIO() (which is writable by default).","Verify the handle with `assert file_handle.writable()` before constructing JsonRowWriter.","If wrapping a stream, implement/forward writable() to return True and support write().","Check that the handle wasn't closed earlier in the code path (closed streams return writable() == False)."],"exampleFix":"// before\nf = open('rows.json', 'rb')\nw = JsonRowWriter(f)\n// after\nf = open('rows.json', 'wb')\nw = JsonRowWriter(f)","handlingStrategy":"type-guard","validationCode":"def assert_writable(handle):\n    if not handle.writable():\n        raise ValueError('JsonRowWriter requires a writable stream')\n    return handle","typeGuard":"def is_writable_stream(h):\n    import io\n    return isinstance(h, io.IOBase) and h.writable() and not h.closed","tryCatchPattern":"try:\n    writer = JsonRowWriter(handle)\nexcept ValueError as e:\n    if str(e) == 'Output stream must be writable':\n        handle = open(path, 'wb')\n        writer = JsonRowWriter(handle)\n    else:\n        raise","preventionTips":["Always open writer destinations with 'wb' mode.","Check handle.writable() and not handle.closed before constructing writers.","Use io.BytesIO() (writable) for in-memory test sinks."],"tags":["python","io","bigquery","writer"],"backgroundTag":"file-write-failed","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"}