JuliusBrussee/caveman · error · TypeError
Expected an Anthropic or AsyncAnthropic client
Error message
Expected an Anthropic or AsyncAnthropic client
What it means
with_caveman_anthropic clones a native Anthropic SDK client with caveman middleware attached. It validates that `client` is an Anthropic or AsyncAnthropic instance; anything else (a different provider client, a wrapper class, None) cannot be cloned, so TypeError is raised.
Solutions
- Construct an anthropic.Anthropic or anthropic.AsyncAnthropic client and pass that instance
- Check the import source — the client must come from the `anthropic` package installed with the extra
- Verify argument order/keywords: client first, then keyword-only runtime and scope
Example fix
// before with_caveman_anthropic(openai_client, runtime=runtime, scope=scope) // after from anthropic import Anthropic client = Anthropic() with_caveman_anthropic(client, runtime=runtime, scope=scope)
Defensive patterns
Strategy: type-guard
Validate before calling
if not isinstance(client, (Anthropic, AsyncAnthropic)):
raise TypeError('with_caveman_anthropic needs an Anthropic/AsyncAnthropic client') Type guard
def is_anthropic_client(client) -> bool:
from anthropic import Anthropic, AsyncAnthropic
return isinstance(client, (Anthropic, AsyncAnthropic)) Try / catch
try:
wrapped = with_caveman_anthropic(client, runtime=runtime, scope=scope)
except TypeError as e:
if 'Anthropic' in str(e):
wrapped = attach_generic_middleware(client, runtime, scope)
else:
raise Prevention
- Type-hint parameters as Anthropic | AsyncAnthropic
- Do not pass mocked or wrapped clients into this API
- Check import source of the client class
When it happens
Trigger: Passing an OpenAI client, an anthropic Beta client, a subclass instance that failed isinstance, or None to with_caveman_anthropic(client=..., runtime=..., scope=...).
Common situations: Refactored code passing a generic client object; using a stubbed/mock client in tests; accidentally swapping client and runtime arguments.
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
- Match the sync/async middleware runtime to the native client
- ASGI requires AsyncMiddlewareRuntime
- Expected an existing native Agno Model
- Install caveman-middleware[anthropic] to use the Anthropic…
- Synchronous Agno calls require MiddlewareRuntime
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/eaa95125f8fcda3d.
Report an issue: GitHub.
Appendix: source
Thrown at packages/middleware/python/caveman_middleware/anthropic.py:114
@dataclass(frozen=True)
class _AsyncRecoveryTool(BetaAsyncBuiltinFunctionTool):
binding: object
definition: str
execute: object
def to_dict(self):
return json.loads(self.definition)
async def call(self, input):
return json.dumps(await self.execute(input), ensure_ascii=False, separators=(",", ":"))
def with_caveman_anthropic(client, *, runtime, scope):
"""Return a native SDK clone. Existing native middleware stays in order."""
if not isinstance(client, (Anthropic, AsyncAnthropic)):
raise TypeError("Expected an Anthropic or AsyncAnthropic client")
async_client = isinstance(client, AsyncAnthropic)
if not isinstance(runtime, AsyncMiddlewareRuntime if async_client else MiddlewareRuntime):
raise TypeError("Match the sync/async middleware runtime to the native client")
version_supported = in_range(__version__, "1.4", "2")
if not version_supported and runtime.mode != "off":
runtime.decline("unsupported_version")
native = client.with_middleware(CavemanAnthropicMiddleware(runtime, scope))
if not version_supported or runtime.mode == "off":
return native
original_runner = native.beta.messages.tool_runner
@functools.wraps(original_runner)
def tool_runner(**params):
supplied = params.get("tools")
if runtime.mode != "compress" or not isinstance(supplied, (list, tuple)):
return original_runner(**params)
names = [(t.get("name") if plain(t) else getattr(t, "name", None)) for t in supplied]
if any(type(name) is not str or not name for name in names) or len(set(names)) != len(names) or "caveman_retrieve" in names:View on GitHub (pinned to 3ee70a1026)