pulumi/pulumi · error · RunError
pulumi.run may only be called once
Error message
pulumi.run may only be called once
What it means
A root Stack can host only one async program registered via pulumi.run. _register_async_program raises RunError if a program is already registered or the registration window has closed (the engine has already taken the program for execution).
Source
Thrown at sdk/python/lib/pulumi/runtime/stack.py:322
def _run_legacy_callback(
self, func: Callable[[], Optional[Awaitable[None]]]
) -> None:
try:
awaitable = func()
# This _should_ be an awaitable but old pulumi executors returned modules here, so we need to handle that
# with a type check rather than just `is not None`.
if isawaitable(awaitable):
_sync_await(awaitable)
finally:
self._finish()
# Intentionally leave this resource installed in case subsequent async work uses it.
def _register_async_program(self, program: _AsyncProgram) -> None:
from ..errors import RunError
if self._async_program is not None or self._async_program_registration_closed:
raise RunError("pulumi.run may only be called once")
self._async_program = program
def _take_async_program(self) -> Optional[_AsyncProgram]:
self._async_program_registration_closed = True
return self._async_program
def _add_program_outputs(self, outputs: Optional["Inputs"]) -> None:
if outputs is None:
return
for name, value in outputs.items():
export(name, value)
def _finish(self) -> None:
"""Register this stack's outputs exactly once."""
if self._outputs_registered:
return
View on GitHub (pinned to 793f7b2e16)
Solutions
- Call pulumi.run exactly once, at the program entry point
- Refactor helper libraries to accept the program function instead of calling pulumi.run themselves
- Move late async work into the single registered program rather than a second pulumi.run call
Example fix
// before
pulumi.run(setup)
pulumi.run(teardown) # RunError: only once
// after
async def program():
await setup()
await teardown()
pulumi.run(program) Defensive patterns
Strategy: validation
Validate before calling
called = False
def register_once(program):
global called
if called:
raise RuntimeError('pulumi.run already invoked')
called = True
pulumi.run(program) Try / catch
from pulumi.errors import RunError
try:
pulumi.run(program)
except RunError as e:
if 'only be called once' in str(e):
logger.error('Duplicate pulumi.run call — consolidate into one program')
raise Prevention
- Call pulumi.run exactly once per process, at the entry point
- Ensure third-party helpers don't call pulumi.run internally
- Put late async work inside the single registered program
When it happens
Trigger: Calling pulumi.run twice within the same Pulumi program execution, or calling it after the runtime has started consuming the registered program (registration closed).
Common situations: Calling pulumi.run both at module top level and inside main(); a helper library that internally calls pulumi.run while the user's program also does; calling pulumi.run late (e.g. in a callback that fires after the engine consumed the program).
Related errors
- when debugging or running explicitly, must call Handshake be
- pulumi.run may only be called while a Pulumi program is runn
- The function passed to pulumi.run must return an awaitable
- Only one root Pulumi Stack may be active at once
- failed to save policy project at %s: %w
AI-assisted analysis of pulumi/pulumi@793f7b2e16 (2026-08-31).
Data as JSON: /api/errors/b09e4ba32f94585c.
Report an issue: GitHub.