apache/beam · error · RuntimeError
Bundle is not in a finalizable state for
Error message
Bundle is not in a finalizable state for %s
What it means
SdkWorkerBundle finalization requires the bundle to be in a state where it can be finalized. If bundle_processor_cache.lookup returns None/raises or the processor for instruction_id is not in a finalizable state, RuntimeError 'Bundle is not in a finalizable state' is raised. Beam notes this happens when finalize arrives while the bundle is still initializing or after it was already finalized and released.
Solutions
- Ensure the runner sends finalize exactly once per successful process_bundle.
- Fix runner-side retries to use a new instruction id rather than re-finalizing a completed one.
- Align runner and SDK harness versions so lifecycle state transitions match.
- If caused by concurrent control messages, serialize finalize handling on the runner or upgrade Beam to a version with the relevant race fixed.
Example fix
# before
await send(ProcessBundle(instruction_id=i))
await send(FinalizeBundle(instruction_id=i))
await send(FinalizeBundle(instruction_id=i)) # retry duplicates finalize
# after
await send(ProcessBundle(instruction_id=i))
if not finalized_ids.add(i):
await send(FinalizeBundle(instruction_id=i)) # finalize only once Defensive patterns
Strategy: validation
Validate before calling
if instruction_id in finalized_instruction_ids:
raise ValueError(f'{instruction_id} already finalized; finalize must be sent once') Try / catch
try:
finalize_bundle(request)
except RuntimeError as e:
if 'not in a finalizable state' in str(e):
log.warning('duplicate/late finalize for %s', request.instruction_id)
return # treat as idempotent no-op if the bundle already completed
raise Prevention
- Send FinalizeBundle exactly once per successful ProcessBundle.
- Use fresh instruction ids for retries instead of re-finalizing.
- Keep runner/harness versions aligned so lifecycle transitions agree.
When it happens
Trigger: A finalize_bundle(request) arrives for an instruction id whose BundleProcessor was already finalized and released, or is still being set up, or was discarded due to failure.
Common situations: Runner retry logic sending finalize twice for one bundle; race between bundle completion and finalize control messages; runner/harness version skew in the bundle lifecycle protocol; very short-lived bundles where finalize is delayed past release.
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
- At least one owner must be registered.
- Buffer counter not initialized for UUID:
- Bundle processing associated with
- Cannot access FinishBundleContext outside of @FinishBundle…
- Cannot access StartBundleContext outside of @StartBundle…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/d554a85d1ee25e4d.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/runners/worker/sdk_worker.py:802
# type: (...) -> beam_fn_api_pb2.InstructionResponse
try:
processor = self.bundle_processor_cache.lookup(request.instruction_id)
except RuntimeError:
return beam_fn_api_pb2.InstructionResponse(
instruction_id=instruction_id, error=traceback.format_exc())
if processor:
try:
finalize_response = processor.finalize_bundle()
self.bundle_processor_cache.release(request.instruction_id)
return beam_fn_api_pb2.InstructionResponse(
instruction_id=instruction_id, finalize_bundle=finalize_response)
except Exception as e:
self.bundle_processor_cache.discard(request.instruction_id, e)
raise
# We can reach this state if there was an erroneous request to finalize
# the bundle while it is being initialized or has already been finalized
# and released.
raise RuntimeError(
'Bundle is not in a finalizable state for %s' % instruction_id)
@contextlib.contextmanager
def maybe_profile(self, instruction_id):
# type: (str) -> Iterator[None]
if self.profiler_factory:
profiler = self.profiler_factory(instruction_id)
if profiler:
with profiler:
yield
else:
yield
else:
yield
class StateHandler(metaclass=abc.ABCMeta):
"""An abstract object representing a ``StateHandler``."""View on GitHub (pinned to 12126d8942)