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_fn

View on GitHub (pinned to e84aa99b32)

Solutions

  1. Register the lifespan only once per Environment; consolidate the two functions into one.
  2. Compose lifespans: call the first function inside the second (or use a stacking helper) instead of overwriting.
  3. If overwriting is intentional, suppress/handle the warning explicitly and document why.
  4. 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

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


AI-assisted analysis of cocoindex-io/cocoindex@e84aa99b32 (2026-09-08). Data as JSON: /api/errors/70d758a5034cad54. Report an issue: GitHub.