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

  1. Have the resolver return Scope(namespace, conversation_id, branch_id, cache_epoch)
  2. Guard against missing state keys and fall back to a default Scope instead of returning None
  3. 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

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


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.stateful

View on GitHub (pinned to 3ee70a1026)