{"record":{"id":"3df713cf94b6525e","repo":"JuliusBrussee/caveman","slug":"strands-scope-resolver-must-return-a-caveman-scope","errorCode":null,"errorMessage":"Strands scope resolver must return a Caveman Scope","messagePattern":"Strands scope resolver must return a Caveman Scope","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/middleware/python/caveman_middleware/strands.py","lineNumber":29,"sourceCode":"    from strands.models.model import Model\n    from strands.plugins import Plugin\n    from strands.types.tools import ToolContext\nexcept ModuleNotFoundError as error:\n    raise ImportError(\"Install caveman-middleware[strands] to use the Strands adapter\") from error\n\nfrom caveman_cloud.middleware import Adapter, Candidate, MiddlewareRuntime, Scope\nfrom caveman_cloud.middleware.runtime import RECOVERY_DESCRIPTION, RECOVERY_SCHEMA\nfrom ._native import Attempt, manifest, owner, plain, replace_path\nfrom ._versions import matches_framework\nfrom ._usage import usage\n\nADAPTER = Adapter(\"strands\", \"0.1.0\", \"1.55.0\", \"strands-content-v1\")\n\n\ndef _scope(source, state):\n    scope = source if isinstance(source, Scope) else source(state or {})\n    if not isinstance(scope, Scope):\n        raise TypeError(\"Strands scope resolver must return a Caveman Scope\")\n    return scope\n\n\nclass CavemanModel(Model):\n    \"\"\"Public native model delegate. A model wrapper alone is recovery-free.\"\"\"\n    def __init__(self, model, *, runtime, scope):\n        if not isinstance(model, Model):\n            raise TypeError(\"Expected a native Strands Model\")\n        self.model = model\n        self.runtime = runtime.as_async() if isinstance(runtime, MiddlewareRuntime) else runtime\n        self.scope, self.registration = scope, None\n        self.version_supported = matches_framework((\"strands-agents\", \"1.55\", \"2\"))\n        if not self.version_supported and self.runtime.mode != \"off\":\n            self.runtime.decline(\"unsupported_version\")\n\n    @property\n    def stateful(self):\n        return self.model.stateful","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/middleware/python/caveman_middleware/strands.py#L11-L47","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ndef scope(state):\n    return state.get(\"scope\")\n// after\ndef scope(state):\n    s = state.get(\"scope\")\n    return s if isinstance(s, Scope) else Scope(\"app\", state[\"session_id\"], \"main\", \"0\")","handlingStrategy":"validation","validationCode":"from caveman_cloud.middleware import Scope\nresult = my_resolver(state or {})\nassert isinstance(result, Scope), \"Strands scope resolver must return a Scope\"","typeGuard":"def is_caveman_scope(x) -> bool:\n    return isinstance(x, Scope)","tryCatchPattern":"try:\n    bundle = make_strands_bundle(rt, scope=my_resolver)\nexcept TypeError as e:\n    if \"must return a Caveman Scope\" in str(e):\n        my_resolver = lambda state: Scope(\"app\", state[\"session_id\"], \"main\", \"0\")\n        bundle = make_strands_bundle(rt, scope=my_resolver)\n    else:\n        raise","preventionTips":["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"],"tags":["python","strands","scope","type-error"],"backgroundTag":"invalid-argument-value","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}