{"record":{"id":"dff3c1316fa5dd56","repo":"apache/beam","slug":"a-context-manager-constructor-not-a-fully-constructed","errorCode":null,"errorMessage":"A context manager constructor (not a fully constructed context manager) must be passed to avoid issues with one-shot managers. For example, write {class_name}(tempfile.TemporaryDirectory, args=(...)) rather than {class_name}(tempfile.TemporaryDirectory(...))","messagePattern":"A context manager constructor \\(not a fully constructed context manager\\) must be passed to avoid issues with one-shot managers\\. For example, write (.+?)\\(tempfile\\.TemporaryDirectory, args=\\(\\.\\.\\.\\)\\) rather than (.+?)\\(tempfile\\.TemporaryDirectory\\(\\.\\.\\.\\)\\)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/transforms/core.py","lineNumber":547,"sourceCode":"    self.watermark_estimator_provider = watermark_estimator_provider\n    self.param_id = 'WatermarkEstimatorProvider'\n\n\nclass _ContextParam(_DoFnParam):\n  def __init__(\n      self, context_manager_constructor, args=(), kwargs=None, *, name=None):\n    class_name = self.__class__.__name__.strip('_')\n    if (not callable(context_manager_constructor) or\n        (hasattr(context_manager_constructor, '__enter__') and\n         len(inspect.signature(\n             context_manager_constructor.__enter__).parameters) == 0)):\n      # Context managers constructed with @contextlib.contextmanager can only\n      # be used once, and in addition cannot be pickled because they invoke\n      # the function on __init__ rather than at __enter__.\n      # In addition, other common context managers such as\n      # tempfile.TemporaryDirectory perform side-effecting actions in __init__\n      # rather than in __enter__.\n      raise TypeError(\n          \"A context manager constructor (not a fully constructed context \"\n          \"manager) must be passed to avoid issues with one-shot managers. \"\n          \"For example, \"\n          \"write {class_name}(tempfile.TemporaryDirectory, args=(...)) \"\n          \"rather than {class_name}(tempfile.TemporaryDirectory(...))\")\n    super().__init__(f'{class_name}_{name or id(self)}')\n    self.context_manager_constructor = context_manager_constructor\n    self.args = args\n    self.kwargs = kwargs or {}\n\n  def create_and_enter(self):\n    cm = self.context_manager_constructor(*self.args, **self.kwargs)\n    return cm, cm.__enter__()\n\n\nclass _BundleContextParam(_ContextParam):\n  \"\"\"Allows one to use a context manager to manage bundle-scoped parameters.\n","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/transforms/core.py#L529-L565","documentation":"Beam's context manager support (e.g. in DoFn/ParDo lifecycle) requires the context manager CLASS (constructor) plus args, not an already-constructed instance. Fully constructed managers may perform side effects at __init__ (like tempfile.TemporaryDirectory creating the directory immediately) or be one-shot/unpicklable when built with @contextlib.contextmanager, so Beam must construct and enter the manager itself at the right lifecycle point.","triggerScenarios":"Passing an already-instantiated context manager to a Beam class that accepts one, e.g. DoFnWithContextManager(tempfile.TemporaryDirectory()) or similar {class_name}(manager) calls in core.py:547 __init__, instead of passing (tempfile.TemporaryDirectory, args=(...)).","commonSituations":"Developers porting plain Python code that uses `with tempfile.TemporaryDirectory() as d:` into a Beam DoFn; using @contextlib.contextmanager generators directly; instantiating the manager inline in a constructor call.","solutions":["Pass the context manager class plus constructor args, e.g. MyDoFn(tempfile.TemporaryDirectory, args=('/tmp/x',)) instead of MyDoFn(tempfile.TemporaryDirectory('/tmp/x')).","For @contextlib.contextmanager-generated managers, pass the generator function and its args so Beam constructs it fresh at __enter__ time.","If the manager needs setup at construction, restructure it so all side effects happen in __enter__."],"exampleFix":"# before\ndo_fn = MyDoFn(tempfile.TemporaryDirectory())\n\n# after\ndo_fn = MyDoFn(tempfile.TemporaryDirectory, args=())","handlingStrategy":"validation","validationCode":"import inspect\ndef check_context_manager_arg(mgr):\n    if inspect.isclass(mgr):\n        return True\n    if hasattr(mgr, '__enter__') and hasattr(mgr, '__exit__'):\n        raise TypeError('Pass the context manager class + args, not an instance: '\n                        f'{type(mgr).__name__} was already constructed')\n    return False","typeGuard":"def is_cm_class(x) -> bool:\n    return inspect.isclass(x) and hasattr(x, '__enter__') and hasattr(x, '__exit__')","tryCatchPattern":"try:\n    do_fn = MyDoFn(cm)\nexcept TypeError as e:\n    if 'context manager constructor' in str(e):\n        do_fn = MyDoFn(type(cm), args=inspect.signature(type(cm)).bind(*()).args)\n    else:\n        raise","preventionTips":["Always pass (ContextManagerClass, args=(...), kwargs={...}) to Beam context-manager-aware classes","Never instantiate @contextlib.contextmanager generators inline in Beam pipeline construction","Keep side effects (mkdir, file creation) in __enter__, not __init__, for managers used in DoFns"],"tags":["python","apache-beam","context-manager","typeerror"],"backgroundTag":"invalid-constructor-argument","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"}