{"record":{"id":"eaa95125f8fcda3d","repo":"JuliusBrussee/caveman","slug":"expected-an-anthropic-or-asyncanthropic-client","errorCode":null,"errorMessage":"Expected an Anthropic or AsyncAnthropic client","messagePattern":"Expected an Anthropic or AsyncAnthropic client","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/middleware/python/caveman_middleware/anthropic.py","lineNumber":114,"sourceCode":"\n\n@dataclass(frozen=True)\nclass _AsyncRecoveryTool(BetaAsyncBuiltinFunctionTool):\n    binding: object\n    definition: str\n    execute: object\n\n    def to_dict(self):\n        return json.loads(self.definition)\n\n    async def call(self, input):\n        return json.dumps(await self.execute(input), ensure_ascii=False, separators=(\",\", \":\"))\n\n\ndef with_caveman_anthropic(client, *, runtime, scope):\n    \"\"\"Return a native SDK clone. Existing native middleware stays in order.\"\"\"\n    if not isinstance(client, (Anthropic, AsyncAnthropic)):\n        raise TypeError(\"Expected an Anthropic or AsyncAnthropic client\")\n    async_client = isinstance(client, AsyncAnthropic)\n    if not isinstance(runtime, AsyncMiddlewareRuntime if async_client else MiddlewareRuntime):\n        raise TypeError(\"Match the sync/async middleware runtime to the native client\")\n    version_supported = in_range(__version__, \"1.4\", \"2\")\n    if not version_supported and runtime.mode != \"off\":\n        runtime.decline(\"unsupported_version\")\n    native = client.with_middleware(CavemanAnthropicMiddleware(runtime, scope))\n    if not version_supported or runtime.mode == \"off\":\n        return native\n    original_runner = native.beta.messages.tool_runner\n\n    @functools.wraps(original_runner)\n    def tool_runner(**params):\n        supplied = params.get(\"tools\")\n        if runtime.mode != \"compress\" or not isinstance(supplied, (list, tuple)):\n            return original_runner(**params)\n        names = [(t.get(\"name\") if plain(t) else getattr(t, \"name\", None)) for t in supplied]\n        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:","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/middleware/python/caveman_middleware/anthropic.py#L96-L132","documentation":"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.","triggerScenarios":"Passing an OpenAI client, an anthropic Beta client, a subclass instance that failed isinstance, or None to with_caveman_anthropic(client=..., runtime=..., scope=...).","commonSituations":"Refactored code passing a generic client object; using a stubbed/mock client in tests; accidentally swapping client and runtime arguments.","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"],"exampleFix":"// before\nwith_caveman_anthropic(openai_client, runtime=runtime, scope=scope)\n// after\nfrom anthropic import Anthropic\nclient = Anthropic()\nwith_caveman_anthropic(client, runtime=runtime, scope=scope)","handlingStrategy":"type-guard","validationCode":"if not isinstance(client, (Anthropic, AsyncAnthropic)):\n    raise TypeError('with_caveman_anthropic needs an Anthropic/AsyncAnthropic client')","typeGuard":"def is_anthropic_client(client) -> bool:\n    from anthropic import Anthropic, AsyncAnthropic\n    return isinstance(client, (Anthropic, AsyncAnthropic))","tryCatchPattern":"try:\n    wrapped = with_caveman_anthropic(client, runtime=runtime, scope=scope)\nexcept TypeError as e:\n    if 'Anthropic' in str(e):\n        wrapped = attach_generic_middleware(client, runtime, scope)\n    else:\n        raise","preventionTips":["Type-hint parameters as Anthropic | AsyncAnthropic","Do not pass mocked or wrapped clients into this API","Check import source of the client class"],"tags":["python","anthropic","typeerror","client"],"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"}