{"record":{"id":"8ce73e7263cebe05","repo":"apache/beam","slug":"cannot-pickle-files-that-are-not-opened-for-reading-s","errorCode":null,"errorMessage":"Cannot pickle files that are not opened for reading: %s","messagePattern":"Cannot pickle files that are not opened for reading: (.+?)","errorType":"exception","errorClass":"PicklingError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/internal/cloudpickle/cloudpickle.py","lineNumber":1084,"sourceCode":"def _file_reduce(obj):\n  \"\"\"Save a file.\"\"\"\n  import io\n\n  if not hasattr(obj, \"name\") or not hasattr(obj, \"mode\"):\n    raise pickle.PicklingError(\n        \"Cannot pickle files that do not map to an actual file\")\n  if obj is sys.stdout:\n    return getattr, (sys, \"stdout\")\n  if obj is sys.stderr:\n    return getattr, (sys, \"stderr\")\n  if obj is sys.stdin:\n    raise pickle.PicklingError(\"Cannot pickle standard input\")\n  if obj.closed:\n    raise pickle.PicklingError(\"Cannot pickle closed files\")\n  if hasattr(obj, \"isatty\") and obj.isatty():\n    raise pickle.PicklingError(\"Cannot pickle files that map to tty objects\")\n  if \"r\" not in obj.mode and \"+\" not in obj.mode:\n    raise pickle.PicklingError(\n        \"Cannot pickle files that are not opened for reading: %s\" % obj.mode)\n\n  name = obj.name\n\n  retval = io.StringIO()\n\n  try:\n    # Read the whole file\n    curloc = obj.tell()\n    obj.seek(0)\n    contents = obj.read()\n    obj.seek(curloc)\n  except OSError as e:\n    raise pickle.PicklingError(\n        \"Cannot pickle file %s as it cannot be read\" % name) from e\n  retval.write(contents)\n  retval.seek(curloc)\n","sourceCodeStart":1066,"sourceCodeEnd":1102,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/internal/cloudpickle/cloudpickle.py#L1066-L1102","documentation":"_file_reduce only supports pickling files open for reading; if the file's mode contains neither 'r' nor '+', it raises pickle.PicklingError('Cannot pickle files that are not opened for reading: <mode>'). The contents are captured by reading the file, which is impossible for write-only handles.","triggerScenarios":"Cloudpickling a file opened with mode 'w', 'a', 'x', 'wb' etc. that is captured in a closure or object being serialized by Beam.","commonSituations":"Log or output files opened for writing that leak into pickled function state; accidentally passing an output handle where an input file was intended; code refactors moving an output file into a captured scope.","solutions":["Open the file in read mode ('r' or 'r+') if its contents should be serialized.","Pass the file path string and reopen with the desired mode inside the worker.","Remove the write handle from the pickled object; write output at the destination via sinks (e.g. WriteToText).","Use 'a+' or 'r+' if both append and read access are needed."],"exampleFix":"// before\nf = open('out.txt', 'w')\nfn_capturing(f)\n// after\npath = 'out.txt'\ndef write():\n  with open(path, 'w') as f: ...","handlingStrategy":"validation","validationCode":"if hasattr(f, 'mode') and 'r' not in f.mode and '+' not in f.mode:\n    raise ValueError(f\"file {f.name} not open for reading: {f.mode}\")","typeGuard":"def is_readable_file(obj):\n    return hasattr(obj, 'mode') and ('r' in obj.mode or '+' in obj.mode)","tryCatchPattern":"try:\n    cloudpickle.dump(fn)\nexcept pickle.PicklingError as e:\n    if 'not opened for reading' in str(e): fn = reopen_readable(fn)\n    else: raise","preventionTips":["Only capture read-mode handles if serializing files","Prefer path-based reopening in workers","Separate input handles (read) from output sinks (write)"],"tags":["python","pickle","serialization","file-mode"],"backgroundTag":"json-serialization-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"}