{"record":{"id":"2c3ce02e79842481","repo":"JuliusBrussee/caveman","slug":"native-tool-is-not-registered","errorCode":null,"errorMessage":"Native tool is not registered","messagePattern":"Native tool is not registered","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/middleware/python/caveman_middleware/llama_index.py","lineNumber":184,"sourceCode":"            and tuple(tool.metadata.name for tool in tools) == self.names\n            and self.runtime.owns_binding(self.binding, self.scope)\n            and self.runtime.owns_binding(self.async_binding, self.scope)\n            and self.tool.fn is self.sync and self.tool.async_fn is self.async_\n            and self.tool.metadata is self.metadata and not self.tool.partial_params and not self.tool.requires_context\n            and self.metadata.description == RECOVERY_DESCRIPTION and not self.metadata.return_direct\n            and self.metadata.get_parameters_dict() == RECOVERY_SCHEMA)\n\n    def invocation(self):\n        return _Invocation(self, self.scope, self.tools, self.successful, True)\n\n    def selected(self, call: ToolSelection):\n        if self.binding is not None and not self.registered(self.tools, self.invocation()):\n            raise ValueError(\"Native executor registration changed\")\n        if not isinstance(call, ToolSelection) or not isinstance(call.tool_id, str) or not call.tool_id or not isinstance(call.tool_kwargs, dict):\n            raise TypeError(\"Expected a native ToolSelection\")\n        matches = [tool for tool in self.tools if tool.metadata.name == call.tool_name]\n        if len(matches) != 1:\n            raise ValueError(\"Native tool is not registered\")\n        self.successful.pop(call.tool_id, None)\n        return matches[0]\n\n    def completed(self, call, result):\n        if not isinstance(result, ToolOutput):\n            raise TypeError(\"Native FunctionTool returned an unexpected output\")\n        if not result.is_error and call.tool_name != \"caveman_retrieve\" and len(self.successful) < 4096:\n            self.successful[call.tool_id] = call.tool_name\n        return result\n\n\n@dataclass(frozen=True)\nclass CavemanLLMTools:\n    \"\"\"Native model and tools for an application-owned loop; no scheduler.\"\"\"\n    model: LLM\n    tools: tuple[FunctionTool, ...]\n    _registration: Any\n","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/middleware/python/caveman_middleware/llama_index.py#L166-L202","documentation":"After validation, selected() looks up exactly one registered tool whose metadata.name matches call.tool_name; zero or multiple matches raise ValueError because the selection cannot be resolved unambiguously.","triggerScenarios":"Dispatching a tool_id/name that is not in the executor's tools list, or after tools were changed so the name no longer matches.","commonSituations":"LLM hallucinating a tool name not registered, tools renamed after registration, or reusing an executor across sessions with different tool sets.","solutions":["Only dispatch tool calls whose tool_name matches a registered tool's metadata.name","Re-register/re-create the executor if the tool set changed","Check membership first: any(t.metadata.name == call.tool_name for t in tools)"],"exampleFix":"// before\nexecutor.selected(call)  # call.tool_name='get_weather' not registered\n// after\nnames = {t.metadata.name for t in executor.tools}\nif call.tool_name in names:\n    executor.selected(call)","handlingStrategy":"validation","validationCode":"registered = {t.metadata.name for t in executor.tools}\nif call.tool_name not in registered:\n    raise KeyError(f\"tool {call.tool_name!r} is not registered\")","typeGuard":"def is_registered(executor, tool_name: str) -> bool:\n    return sum(t.metadata.name == tool_name for t in executor.tools) == 1","tryCatchPattern":"try:\n    tool = executor.selected(call)\nexcept ValueError as e:\n    log.warning(\"dispatch skipped: %s\", e)\n    return error_tool_output(call)","preventionTips":["Constrain the LLM's tool choices to registered names","Re-register the executor after any tool renaming","Log hallucinated tool names instead of dispatching them"],"tags":["python","llamaindex","tool-lookup"],"backgroundTag":"entity-not-found","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"}