apache/beam · error · TypeError
A context manager constructor (not a fully constructed conte
Error message
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(...)) What it means
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.
Source
Thrown at sdks/python/apache_beam/transforms/core.py:547
self.watermark_estimator_provider = watermark_estimator_provider
self.param_id = 'WatermarkEstimatorProvider'
class _ContextParam(_DoFnParam):
def __init__(
self, context_manager_constructor, args=(), kwargs=None, *, name=None):
class_name = self.__class__.__name__.strip('_')
if (not callable(context_manager_constructor) or
(hasattr(context_manager_constructor, '__enter__') and
len(inspect.signature(
context_manager_constructor.__enter__).parameters) == 0)):
# Context managers constructed with @contextlib.contextmanager can only
# be used once, and in addition cannot be pickled because they invoke
# the function on __init__ rather than at __enter__.
# In addition, other common context managers such as
# tempfile.TemporaryDirectory perform side-effecting actions in __init__
# rather than in __enter__.
raise TypeError(
"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(...))")
super().__init__(f'{class_name}_{name or id(self)}')
self.context_manager_constructor = context_manager_constructor
self.args = args
self.kwargs = kwargs or {}
def create_and_enter(self):
cm = self.context_manager_constructor(*self.args, **self.kwargs)
return cm, cm.__enter__()
class _BundleContextParam(_ContextParam):
"""Allows one to use a context manager to manage bundle-scoped parameters.
View on GitHub (pinned to 12126d8942)
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__.
Example fix
# before do_fn = MyDoFn(tempfile.TemporaryDirectory()) # after do_fn = MyDoFn(tempfile.TemporaryDirectory, args=())
Defensive patterns
Strategy: validation
Validate before calling
import inspect
def check_context_manager_arg(mgr):
if inspect.isclass(mgr):
return True
if hasattr(mgr, '__enter__') and hasattr(mgr, '__exit__'):
raise TypeError('Pass the context manager class + args, not an instance: '
f'{type(mgr).__name__} was already constructed')
return False Type guard
def is_cm_class(x) -> bool:
return inspect.isclass(x) and hasattr(x, '__enter__') and hasattr(x, '__exit__') Try / catch
try:
do_fn = MyDoFn(cm)
except TypeError as e:
if 'context manager constructor' in str(e):
do_fn = MyDoFn(type(cm), args=inspect.signature(type(cm)).bind(*()).args)
else:
raise Prevention
- 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
When it happens
Trigger: 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=(...)).
Common situations: 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.
Related errors
- text_splitter must be a LangChain TextSplitter
- @yields_elements must be applied to a process or process_bat
- DoFn {self!r} yields element from both process and process_b
- Either {self.__class__.__name__}.process_batch() must have a
- DoFn {self!r} yields batches from both process and process_b
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/dff3c1316fa5dd56.
Report an issue: GitHub.