JuliusBrussee/caveman · error · ValueError
ASGI context resolver or request bounds are invalid
Error message
ASGI context resolver or request bounds are invalid
What it means
CavemanASGIMiddleware validates the resolve_context callable and the request-size bounds in __init__. resolve_context must be callable, max_body_bytes must be between 1 and 2 MiB (2<<20), and max_request_chunks between 1 and 4096. This guards against a resolver that can never authenticate context and against buffer bounds that would either disable body buffering entirely or allow unbounded memory growth.
Solutions
- Keep max_body_bytes within 1..2097152; if payloads exceed 2 MiB, split or compress them upstream rather than raising the bound
- Keep max_request_chunks within 1..4096
- Ensure resolve_context is a callable (sync or async) accepting one ASGI scope argument; wrap it in a function if it is a method-like object
- Check for values passed as strings from environment/config; convert with int() before constructing
Example fix
// before mw = CavemanASGIMiddleware(app, runtime=rt, routes=routes, resolve_context=None, max_body_bytes=16<<20) // after mw = CavemanASGIMiddleware(app, runtime=rt, routes=routes, resolve_context=my_resolver, max_body_bytes=2<<20)
Defensive patterns
Strategy: validation
Validate before calling
assert callable(resolve_context), 'resolve_context must be callable'
assert 1 <= max_body_bytes <= 2 << 20, f'max_body_bytes out of range: {max_body_bytes}'
assert 1 <= max_request_chunks <= 4096, f'max_request_chunks out of range: {max_request_chunks}' Try / catch
try:
mw = CavemanASGIMiddleware(app, runtime=rt, routes=routes, resolve_context=resolver, max_body_bytes=body_cap, max_request_chunks=chunks)
except ValueError as e:
logging.critical('invalid ASGI middleware config: %s', e)
raise Prevention
- Coerce config values from env/JSON with int() before passing them
- Remember the 2 MiB hard ceiling; design payloads to fit rather than raising bounds
- Keep the resolver a plain function so it is always callable
When it happens
Trigger: Passing resolve_context=None or a non-callable; passing max_body_bytes=0 or > 2097152 (e.g. 10<<20 to 'raise the limit'); passing max_request_chunks=0 or > 4096; passing these as strings or misremembering which keyword takes which bound.
Common situations: Developers try to lift the 2 MiB body cap for large LLM payloads (e.g. big batched requests), copy a config where bounds were supplied as env-var strings, or refactor and swap resolve_context for a non-callable object holding the resolver.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Configure exact POST paths and native LLM protocols
- initialToolCount must be a non-negative integer
- invalid_configuration
- apiKey, baseURL, and agent are required
- artifact_id is required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/5cbc2f07b68df43f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/asgi.py:70
class CavemanASGIMiddleware:
"""Place inside authentication and original-content guard middleware.
resolve_context may decline by returning None; existing application routing
and auth then run unchanged. It must use authenticated server state, not
namespace/session headers. This middleware never handles an auth rejection.
"""
def __init__(self, app, *, runtime: AsyncMiddlewareRuntime,
routes: Mapping[str, Protocol],
resolve_context: Callable[[ASGIScope], ASGIContext | None | Awaitable[ASGIContext | None]],
max_body_bytes: int = 2 << 20, max_request_chunks: int = 256):
if not isinstance(runtime, AsyncMiddlewareRuntime):
raise TypeError("ASGI requires AsyncMiddlewareRuntime")
if not routes or any(not isinstance(path, str) or not path.startswith("/") or "*" in path or "?" in path
or protocol not in ("openai-chat", "openai-responses", "anthropic-messages") for path, protocol in routes.items()):
raise ValueError("Configure exact POST paths and native LLM protocols")
if not callable(resolve_context) or not 1 <= max_body_bytes <= 2 << 20 or not 1 <= max_request_chunks <= 4096:
raise ValueError("ASGI context resolver or request bounds are invalid")
self.app, self.runtime = app, runtime
self.routes, self.resolve_context = dict(routes), resolve_context
self.max_body_bytes, self.max_request_chunks = max_body_bytes, max_request_chunks
self._version_supported = matches_framework(("fastapi", "0.141", "1"), ("starlette", "1.6", "2"))
if not self._version_supported and runtime.mode != "off":
runtime.decline("unsupported_version")
async def __call__(self, scope, receive, send):
if owner.get() is not None:
return await self.app(scope, receive, send)
protocol = self.routes.get(scope.get("path"))
async def passthrough(reader, reason):
if scope.get("type") != "http" or scope.get("method") != "POST" or protocol is None:
self.runtime.report(None, reason=reason, adapter="asgi")
return await self.app(scope, reader, send)
# This exact inference route still owns its native request when
# projection is disabled or declined. A nested adapter must notView on GitHub (pinned to 3ee70a1026)