cocoindex-io/cocoindex · warning
Overriding the default lifespan function {self._lifespan_fn}
Error message
Overriding the default lifespan function {self._lifespan_fn} with {fn}. What it means
Environment.lifespan() registers the lifespan function; if one was already registered, the old one is overwritten and a warning (not an error) is emitted showing both functions. This usually means two parts of the program each tried to set the app's lifespan, so one provider silently stops being used.
Source
Thrown at python/cocoindex/_internal/environment.py:332
self._lifespan_fn = None
self._exit_stack = None
self._env = None
self._info = EnvironmentInfo(self)
def _get_start_stop_lock(self) -> asyncio.Lock:
"""Get or create the start/stop lock (must be called from async context)."""
if self._start_stop_lock is None:
self._start_stop_lock = asyncio.Lock()
return self._start_stop_lock
@property
def name(self) -> str:
return self._name
def lifespan(self, fn: LifespanFn) -> None:
with self._lifespan_fn_lock:
if self._lifespan_fn is not None:
warnings.warn(
f"Overriding the default lifespan function {self._lifespan_fn} with {fn}."
)
self._lifespan_fn = fn
async def _reset(self) -> None:
await self.stop()
with self._lifespan_fn_lock:
self._lifespan_fn = None
async def _get_env(self) -> Environment:
"""
Start the default environment (executes on the default environment's event loop).
"""
async with self._get_start_stop_lock():
if self._env is not None:
return self._env
with self._lifespan_fn_lock:
fn = self._lifespan_fn or _noop_lifespan_fnView on GitHub (pinned to e84aa99b32)
Solutions
- Register the lifespan only once per Environment; consolidate the two functions into one.
- Compose lifespans: call the first function inside the second (or use a stacking helper) instead of overwriting.
- If overwriting is intentional, suppress/handle the warning explicitly and document why.
- Ensure setup helpers are idempotent (guard with a flag) so lifespan isn't set twice.
Example fix
# before
env.lifespan(setup_db)
env.lifespan(setup_cache) # overwrites setup_db
# after
async def combined():
await setup_db()
await setup_cache()
env.lifespan(combined) Defensive patterns
Strategy: validation
Validate before calling
assert env._lifespan_fn is None, "lifespan already registered; compose instead of overriding"
Try / catch
import warnings
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
env.lifespan(fn)
if any("Overriding the default lifespan" in str(x.message) for x in w):
raise RuntimeError("lifespan registered twice — compose the functions instead") Prevention
- Register lifespan exactly once per Environment, ideally in a single bootstrap function.
- Compose multiple setup steps into one lifespan function.
- Treat this warning as an error in CI with `-W error::UserWarning` filters.
When it happens
Trigger: Calling env.lifespan(fn) twice on the same Environment — e.g. a library sets a default lifespan and app code sets another, or a setup helper is invoked twice (common with test fixtures and app re-initialization).
Common situations: Combining cocoindex helpers that internally call lifespan() with your own lifespan registration; running tests where a module-level setup and a per-test fixture both configure the same Environment; duplicated app bootstrap code after a refactor.
Related errors
- An app named '{name}' is already registered in this environm
- use_mount() requires a ComponentSubpath when the function ha
- LiveComponent classes cannot be used with use_mount(). Use m
- mount() requires a ComponentSubpath when the function has no
- mount_each() requires a ComponentSubpath when the function h
AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08).
Data as JSON: /api/errors/70d758a5034cad54.
Report an issue: GitHub.