{"record":{"id":"7a69fecfc68bb439","repo":"run-llama/llama_index","slug":"tool-tool-metadata-name-is-not-a-functiontool-c","errorCode":null,"errorMessage":"Tool {tool.metadata.name} is not a FunctionTool. CodeActAgent only supports Functions and FunctionTools.","messagePattern":"Tool (.+?) is not a FunctionTool\\. CodeActAgent only supports Functions and FunctionTools\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/agent/workflow/codeact_agent.py","lineNumber":144,"sourceCode":"        \"\"\"Get the tool functions while validating that they are valid tools for the CodeActAgent.\"\"\"\n        callables = []\n        for tool in tools:\n            if (\n                tool.metadata.name == \"handoff\"\n                or tool.metadata.name == EXECUTE_TOOL_NAME\n            ):\n                continue\n\n            if isinstance(tool, FunctionTool):\n                if tool.requires_context:\n                    raise ValueError(\n                        f\"Tool {tool.metadata.name} requires context. \"\n                        \"CodeActAgent only supports tools that do not require context.\"\n                    )\n\n                callables.append(tool.real_fn)\n            else:\n                raise ValueError(\n                    f\"Tool {tool.metadata.name} is not a FunctionTool. \"\n                    \"CodeActAgent only supports Functions and FunctionTools.\"\n                )\n\n        return callables\n\n    def _extract_code_from_response(self, response_text: str) -> Optional[str]:\n        \"\"\"\n        Extract code from the LLM response using XML-style <execute> tags.\n\n        Args:\n            response_text: The LLM response text\n\n        Returns:\n            Extracted code or None if no code found\n\n        \"\"\"\n        # Match content between <execute> and </execute> tags","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/agent/workflow/codeact_agent.py#L126-L162","documentation":"FunctionTool.call raises when the wrapped function was declared with a Context parameter (requires_context, detected via _is_context_param on the signature) but the required context keyword (ctx_param_name) is absent from the merged call kwargs (defaults + partial_params + kwargs). Context-aware tools must be invoked with a Context object supplied by the agent/workflow runtime.","triggerScenarios":"Calling tool.call(query='hi') directly instead of through an agent run when the fn signature has ctx: Context; invoking a context-requiring tool from a framework path that does not inject Context (custom runner, plain __call__ outside Workflow/AgentWorkflow); renaming the ctx parameter so _is_context_param no longer matches.","commonSituations":"Testing context tools outside the workflow runtime; hand-rolled agent loops that call tools manually; upgrading to workflows where ctx injection only happens via handler.run(...); partial_params set for everything except the context.","solutions":["Invoke the tool through the Workflow/AgentWorkflow runtime (e.g. ctx.run or agent handler) so Context is injected automatically.","In direct tests, pass a Context explicitly: tool.call(ctx=Context(workflow)) or the ctx parameter name declared in the signature.","Remove the Context parameter (and requires_context implication) if the tool does not actually need workflow state.","Pre-check tool.requires_context before calling manually and construct an appropriate Context."],"exampleFix":"# before\nasync def my_tool(query: str, ctx: Context) -> str: ...\ntool = FunctionTool.from_defaults(fn=my_tool)\nout = tool.call(query=\"hi\")  # ValueError: Context is required for this tool\n\n# after\nfrom llama_index.core.workflow.context import Context\nctx = Context(workflow=MyWorkflow())\nout = tool.call(query=\"hi\", ctx=ctx)","handlingStrategy":"validation","validationCode":"if tool.requires_context:\n    assert tool.ctx_param_name, 'context param undetected'\n    kwargs[tool.ctx_param_name] = ctx  # ctx from workflow runtime\ntool.call(**kwargs)","typeGuard":"def tool_needs_context(tool) -> bool:\n    return bool(getattr(tool, \"requires_context\", False))","tryCatchPattern":"try:\n    out = tool.call(**kwargs)\nexcept ValueError as e:\n    if \"Context is required\" in str(e):\n        out = tool.call(**kwargs, **{tool.ctx_param_name: make_context()})\n    else:\n        raise","preventionTips":["Run context-requiring tools inside Workflow/AgentWorkflow so ctx is injected.","Pass Context explicitly in manual/test calls.","Check tool.requires_context before dispatching outside the runtime."],"tags":["tools","context","workflows","llama-index"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}