JuliusBrussee/caveman · error · TypeError
Strands scope resolver must return a Caveman Scope
Error message
Strands scope resolver must return a Caveman Scope
What it means
The Strands adapter accepts a Scope instance or a callable resolver receiving the agent state. _scope validates the result and raises TypeError if it is not a caveman_cloud.middleware.Scope, since session addressing requires that type.
Solutions
- Have the resolver return Scope(namespace, conversation_id, branch_id, cache_epoch)
- Guard against missing state keys and fall back to a default Scope instead of returning None
- Confirm the Scope import comes from caveman_cloud.middleware
Example fix
// before
def scope(state):
return state.get("scope")
// after
def scope(state):
s = state.get("scope")
return s if isinstance(s, Scope) else Scope("app", state["session_id"], "main", "0") Defensive patterns
Strategy: validation
Validate before calling
from caveman_cloud.middleware import Scope
result = my_resolver(state or {})
assert isinstance(result, Scope), "Strands scope resolver must return a Scope" Type guard
def is_caveman_scope(x) -> bool:
return isinstance(x, Scope) Try / catch
try:
bundle = make_strands_bundle(rt, scope=my_resolver)
except TypeError as e:
if "must return a Caveman Scope" in str(e):
my_resolver = lambda state: Scope("app", state["session_id"], "main", "0")
bundle = make_strands_bundle(rt, scope=my_resolver)
else:
raise Prevention
- Always construct and return Scope from resolvers; use .get with defaults for state fields
- Never return None on missing state keys — fall back to a default Scope
- Verify the Scope import source
- Assert resolver output type in unit tests
When it happens
Trigger: Providing a scope resolver to the Strands model/bundle that returns a dict, string, or None instead of Scope — e.g. returning state.get("scope") where the key is absent.
Common situations: Resolvers ported from another adapter's API shape; state dicts that lack the fields the resolver expects so it returns None; importing a different Scope class than caveman_cloud.middleware.Scope.
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
- Agno scope resolver must return a Caveman Scope
- AutoGen requires a stable Caveman Scope for each agent or…
- Expected a native Strands Model
- LiteLLM scope must be a trusted Caveman Scope
- Pydantic AI scope resolver must return a Caveman Scope
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/3df713cf94b6525e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/strands.py:29
from strands.models.model import Model
from strands.plugins import Plugin
from strands.types.tools import ToolContext
except ModuleNotFoundError as error:
raise ImportError("Install caveman-middleware[strands] to use the Strands adapter") from error
from caveman_cloud.middleware import Adapter, Candidate, MiddlewareRuntime, Scope
from caveman_cloud.middleware.runtime import RECOVERY_DESCRIPTION, RECOVERY_SCHEMA
from ._native import Attempt, manifest, owner, plain, replace_path
from ._versions import matches_framework
from ._usage import usage
ADAPTER = Adapter("strands", "0.1.0", "1.55.0", "strands-content-v1")
def _scope(source, state):
scope = source if isinstance(source, Scope) else source(state or {})
if not isinstance(scope, Scope):
raise TypeError("Strands scope resolver must return a Caveman Scope")
return scope
class CavemanModel(Model):
"""Public native model delegate. A model wrapper alone is recovery-free."""
def __init__(self, model, *, runtime, scope):
if not isinstance(model, Model):
raise TypeError("Expected a native Strands Model")
self.model = model
self.runtime = runtime.as_async() if isinstance(runtime, MiddlewareRuntime) else runtime
self.scope, self.registration = scope, None
self.version_supported = matches_framework(("strands-agents", "1.55", "2"))
if not self.version_supported and self.runtime.mode != "off":
self.runtime.decline("unsupported_version")
@property
def stateful(self):
return self.model.statefulView on GitHub (pinned to 3ee70a1026)