{"record":{"id":"e1be7ce9f3869299","repo":"JuliusBrussee/caveman","slug":"not-registered","errorCode":"not_registered","errorMessage":"Use CavemanLiteLLM as a context manager while sync Router calls and streams are active","messagePattern":"Use CavemanLiteLLM as a context manager while sync Router calls and streams are active","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"packages/middleware/python/caveman_middleware/litellm.py","lineNumber":311,"sourceCode":"            attempt = Attempt(self.runtime, None, str(uuid.uuid4()), str(uuid.uuid4()), passive=True,\n                              reason=passive_reason, adapter=\"litellm\")\n            attempt.observe(\"dispatch_intent\")\n            token = owner.set(attempt)\n            try:\n                return function(**kwargs)\n            finally:\n                owner.reset(token)\n        if not isinstance(self.runtime, MiddlewareRuntime):\n            raise TypeError(\"Synchronous LiteLLM calls require MiddlewareRuntime\")\n        router = isinstance(self.client, native.Router) and method == \"completion\"\n        if router and self.runtime.strict:\n            # Logging callbacks swallow their exceptions. Reject this capability\n            # before calling the Router so strict failure cannot dispatch a request.\n            self._report(\"unsupported_sync_router_strict\")\n            raise MiddlewareError(\"unsupported_sync_router_strict\")\n        if router and self._registrations == 0:\n            self._report(\"not_registered\")\n            raise RuntimeError(\"Use CavemanLiteLLM as a context manager while sync Router calls and streams are active\")\n        with self._activation(scope, kwargs, method) as (params, request):\n            if router:\n                token = _sync_router.set(self)\n                try:\n                    return function(**params)\n                finally:\n                    _sync_router.reset(token)\n            # Direct sync SDK calls already name the selected provider/model.\n            session = self._session(request, method, self.runtime) if self.client is native else None\n            token = owner.set(None)\n            try:\n                body, attempt = session.prepare(params) if session else (params, None)\n            finally:\n                owner.reset(token)\n            if attempt:\n                body = {**body, \"litellm_call_id\": str(uuid.uuid4())}\n                attempt.observe(\"dispatch_intent\")\n                self._save_attempt(body, attempt)","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/middleware/python/caveman_middleware/litellm.py#L293-L329","documentation":"Sync Router calls and streams rely on callbacks the adapter registers when the CavemanLiteLLM context manager is entered (_registrations counter). If completion() runs on a Router with zero registrations, the adapter reports 'not_registered' and raises RuntimeError telling you to use it as a context manager.","triggerScenarios":"Calling completion() on a litellm.Router-backed adapter without entering `with adapter:` (or after the context manager has exited, when _registrations is back to 0).","commonSituations":"Long-lived adapter stored on a module/class and called directly; entering the context manager in one function and calling completion in another; forgetting the with-block in scripts and notebooks.","solutions":["Wrap sync Router usage: with adapter: adapter.completion(...)","Keep the adapter instance used inside the with-block scope for the whole call/stream duration","If you already use a with-block, ensure completion() is not called after exit (move it inside)","Check that __enter__ actually ran — e.g. no early return between construction and use"],"exampleFix":"// before\nadapter = CavemanLiteLLM(runtime=runtime, client=router)\nadapter.completion(scope=scope, ...)  # RuntimeError: not_registered\n\n// after\nwith CavemanLiteLLM(runtime=runtime, client=router) as adapter:\n    adapter.completion(scope=scope, ...)","handlingStrategy":"try-catch","validationCode":"if getattr(adapter, \"_registrations\", 1) == 0:\n    raise RuntimeError(\"enter 'with adapter:' before sync Router completion calls\")","typeGuard":"def router_context_active(adapter) -> bool:\n    return getattr(adapter, \"_registrations\", 0) > 0","tryCatchPattern":"try:\n    return adapter.completion(scope=scope, **kwargs)\nexcept RuntimeError as e:\n    if \"context manager\" in str(e):\n        with adapter:\n            return adapter.completion(scope=scope, **kwargs)","preventionTips":["Always use `with adapter:` around sync Router completion and streams","Keep the completion call inside the same function that opens the context manager","Enforce the pattern with a team lint rule or wrapper helper","Never store a bare adapter for direct calls; store a factory that returns a context-managed session"],"tags":["python","runtime-error","context-manager","router","litellm"],"backgroundTag":"invalid-state-transition","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}