JuliusBrussee/caveman · error · MiddlewareError
unsupported_sync_router_strict
unsupported_sync_router_strict
Error message
unsupported_sync_router_strict
What it means
Sync litellm.Router completion runs logging callbacks that swallow exceptions, so in strict mode a middleware failure could not abort the request — the strict guarantee would be silently broken. The adapter rejects this combination up front (before the Router dispatches) by reporting 'unsupported_sync_router_strict' and raising MiddlewareError with that code.
Solutions
- Switch sync Router calls to await acompletion(...) (async path), keeping strict mode on
- Disable strict mode on the MiddlewareRuntime if you must keep sync Router calls
- Use a plain litellm client (non-Router) for sync completion calls
- Gate strict mode per-environment so sync-Router deployments run non-strict
Example fix
// before # runtime = MiddlewareRuntime(strict=True); client = litellm.Router(...) adapter.completion(scope=scope, model=..., messages=...) # MiddlewareError // after await adapter.acompletion(scope=scope, model=..., messages=...) # strict-safe
Defensive patterns
Strategy: try-catch
Validate before calling
from litellm import Router
if isinstance(adapter.client, Router) and getattr(adapter.runtime, "strict", False):
raise RuntimeError("sync Router completion is unsupported with strict=True; use acompletion or disable strict") Type guard
def sync_router_strict_supported(adapter) -> bool:
from litellm import Router
return not (isinstance(adapter.client, Router) and adapter.runtime.strict) Try / catch
try:
return adapter.completion(scope=scope, **kwargs)
except MiddlewareError as e:
if e.code == "unsupported_sync_router_strict":
return await adapter.acompletion(scope=scope, **kwargs) Prevention
- Use async Router calls (acompletion) whenever strict mode is enabled
- Keep strict mode off for deployments pinned to sync Router traffic
- Check the strict/Router combination in startup config validation
- Read MiddlewareError.code to branch on specific capability rejections
When it happens
Trigger: Calling completion() while self.client is a litellm.Router, method is 'completion', and self.runtime.strict is True.
Common situations: Enabling strict mode in production config while still using the sync Router for load balancing/fallbacks; flipping runtime.strict on without migrating sync Router traffic to acompletion.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- code
- Install caveman-middleware[litellm] to use the LiteLLM…
- LiteLLM metadata must be a native dictionary
- LiteLLM scope must be a trusted Caveman Scope
- not_registered
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/8286185529bb0c6f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/litellm.py:308
return function(**kwargs)
passive_reason = self._passive_reason(method, kwargs)
if passive_reason:
attempt = Attempt(self.runtime, None, str(uuid.uuid4()), str(uuid.uuid4()), passive=True,
reason=passive_reason, adapter="litellm")
attempt.observe("dispatch_intent")
token = owner.set(attempt)
try:
return function(**kwargs)
finally:
owner.reset(token)
if not isinstance(self.runtime, MiddlewareRuntime):
raise TypeError("Synchronous LiteLLM calls require MiddlewareRuntime")
router = isinstance(self.client, native.Router) and method == "completion"
if router and self.runtime.strict:
# Logging callbacks swallow their exceptions. Reject this capability
# before calling the Router so strict failure cannot dispatch a request.
self._report("unsupported_sync_router_strict")
raise MiddlewareError("unsupported_sync_router_strict")
if router and self._registrations == 0:
self._report("not_registered")
raise RuntimeError("Use CavemanLiteLLM as a context manager while sync Router calls and streams are active")
with self._activation(scope, kwargs, method) as (params, request):
if router:
token = _sync_router.set(self)
try:
return function(**params)
finally:
_sync_router.reset(token)
# Direct sync SDK calls already name the selected provider/model.
session = self._session(request, method, self.runtime) if self.client is native else None
token = owner.set(None)
try:
body, attempt = session.prepare(params) if session else (params, None)
finally:
owner.reset(token)
if attempt:View on GitHub (pinned to 3ee70a1026)