JuliusBrussee/caveman · error · TypeError
Expected a native Strands Model
Error message
Expected a native Strands Model
What it means
CavemanModel for Strands delegates stream/structured calls to a native strands Model instance. The constructor type-checks the model argument; passing anything else (a model id string, a Bedrock client, None) is rejected with a TypeError.
Solutions
- Pass an instantiated native model, e.g. CavemanModel(BedrockModel(model_id="us.anthropic.claude-..."), runtime=..., scope=...)
- Build the underlying model via the strands provider classes before wrapping
- Validate with isinstance(model, Model) before constructing CavemanModel
Example fix
// before
model = CavemanModel("us.anthropic.claude-3-7-sonnet-20250219-v1:0", runtime=rt, scope=scope)
// after
from strands.models.bedrock import BedrockModel
model = CavemanModel(BedrockModel(model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0"), runtime=rt, scope=scope) Defensive patterns
Strategy: type-guard
Validate before calling
from strands.models.model import Model assert isinstance(model, Model), "CavemanModel needs a native strands Model instance"
Type guard
def is_strands_model(x) -> bool:
return isinstance(x, Model) Try / catch
try:
model = CavemanModel(model_arg, runtime=rt, scope=scope)
except TypeError as e:
if "native Strands Model" in str(e):
model_arg = BedrockModel(model_id=str(model_arg))
model = CavemanModel(model_arg, runtime=rt, scope=scope)
else:
raise Prevention
- Build the model with strands provider classes (BedrockModel, AnthropicModel, ...) before wrapping
- Never pass model-id strings or raw cloud clients to CavemanModel
- Validate isinstance(x, Model) at configuration load time
- Use real Model instances in tests rather than plain mocks
When it happens
Trigger: Calling CavemanModel("us.anthropic.claude-...") with a model ID string; passing a boto3 client or a config dict instead of a strands.models.model.Model instance.
Common situations: Confusing Bedrock model identifiers with instantiated Strands Model objects; refactoring from another framework where models were referenced by name; mocks in tests that do not subclass strands Model.
Related errors
- Expected an AutoGen ChatCompletionClient
- Expected an AutoGen Workbench or list of workbenches
- Expected an existing native LlamaIndex LLM
- Expected an existing native Pydantic AI Model
- Strands scope resolver must return a Caveman Scope
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/321ac5b7716ae5d3.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/strands.py:37
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
def update_config(self, **model_config):
return self.model.update_config(**model_config)
def get_config(self):
return self.model.get_config()
async def count_tokens(self, *args, **kwargs):View on GitHub (pinned to 3ee70a1026)