{"record":{"id":"eb06e2cd366de97f","repo":"PrefectHQ/fastmcp","slug":"cannot-compose-lifespan-with-type-other-name","errorCode":null,"errorMessage":"Cannot compose Lifespan with {type(other).__name__}. Use @lifespan decorator or wrap with ContextManagerLifespan().","messagePattern":"Cannot compose Lifespan with (.+?)\\. Use @lifespan decorator or wrap with ContextManagerLifespan\\(\\)\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/lifespan.py","lineNumber":103,"sourceCode":"            The lifespan context dict.\n        \"\"\"\n        async with asynccontextmanager(self._fn)(server) as result:\n            yield result if result is not None else {}\n\n    def __or__(self, other: Lifespan) -> ComposedLifespan:\n        \"\"\"Compose with another lifespan using the | operator.\n\n        Args:\n            other: Another Lifespan instance.\n\n        Returns:\n            A ComposedLifespan that runs both lifespans.\n\n        Raises:\n            TypeError: If other is not a Lifespan instance.\n        \"\"\"\n        if not isinstance(other, Lifespan):\n            raise TypeError(\n                f\"Cannot compose Lifespan with {type(other).__name__}. \"\n                f\"Use @lifespan decorator or wrap with ContextManagerLifespan().\"\n            )\n        return ComposedLifespan(self, other)\n\n\nclass ContextManagerLifespan(Lifespan):\n    \"\"\"Lifespan wrapper for already-wrapped context manager functions.\n\n    Use this for functions already decorated with @asynccontextmanager.\n    \"\"\"\n\n    _fn: LifespanContextManagerFn  # Override type for this subclass\n\n    def __init__(self, fn: LifespanContextManagerFn) -> None:\n        \"\"\"Initialize with a context manager factory function.\"\"\"\n        self._fn = fn\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/lifespan.py#L85-L121","documentation":"Lifespan.__or__ composes two Lifespan instances into a ComposedLifespan. Composing with anything that is not a Lifespan instance (e.g. a raw async context manager, an async generator function, or None) raises TypeError, telling you to decorate the callable with @lifespan or wrap it in ContextManagerLifespan().","triggerScenarios":"Writing fastmcp_lifespan | my_asynccontextmanager, or lifespan_a | lifespan_b where lifespan_b is a plain function/context manager rather than a Lifespan object.","commonSituations":"Mixing the @lifespan decorator style with @asynccontextmanager-produced context managers; passing the undecorated function itself instead of its result; chaining with | in a pipeline where one element lost its wrapper.","solutions":["Decorate the raw callable with the @lifespan decorator before composing.","Wrap a context manager with ContextManagerLifespan(cm) before using |.","Compose using only Lifespan instances on both sides of the | operator."],"exampleFix":"// before\ncombined = server_lifespan | my_cm  # TypeError\n// after\nfrom fastmcp.server.lifespan import ContextManagerLifespan\ncombined = server_lifespan | ContextManagerLifespan(my_cm)","handlingStrategy":"type-guard","validationCode":"def is_composable(other) -> bool:\n    from fastmcp.server.lifespan import Lifespan\n    return isinstance(other, Lifespan)","typeGuard":"def as_lifespan(other):\n    from fastmcp.server.lifespan import Lifespan, ContextManagerLifespan\n    if isinstance(other, Lifespan):\n        return other\n    return ContextManagerLifespan(other)","tryCatchPattern":"try:\n    combined = a | b\nexcept TypeError as e:\n    combined = a | ContextManagerLifespan(b)","preventionTips":["Decorate lifespan callables with @lifespan, not @asynccontextmanager, when composing","Wrap raw context managers with ContextManagerLifespan before using |","assert isinstance(x, Lifespan) at composition sites"],"tags":["lifespan","type-error","composition"],"backgroundTag":"type-composition-mismatch","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}