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

  1. Keep max_body_bytes within 1..2097152; if payloads exceed 2 MiB, split or compress them upstream rather than raising the bound
  2. Keep max_request_chunks within 1..4096
  3. 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
  4. 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

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


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 not

View on GitHub (pinned to 3ee70a1026)