{"record":{"id":"f3bd0ed493c981d9","repo":"run-llama/llama_index","slug":"tool-tool-metadata-name-requires-context-codeac","errorCode":null,"errorMessage":"Tool {tool.metadata.name} requires context. CodeActAgent only supports tools that do not require context.","messagePattern":"Tool (.+?) requires context\\. CodeActAgent only supports tools that do not require context\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"llama-index-core/llama_index/core/agent/workflow/codeact_agent.py","lineNumber":137,"sourceCode":"            llm=llm,\n            code_act_system_prompt=code_act_system_prompt,\n            code_execute_fn=code_execute_fn,\n            streaming=streaming,\n        )\n\n    def _get_tool_fns(self, tools: Sequence[BaseTool]) -> List[Callable]:\n        \"\"\"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:","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/run-llama/llama_index/blob/afd0fef371831f9bda13e5af7167cf4e981278ab/llama-index-core/llama_index/core/agent/workflow/codeact_agent.py#L119-L155","documentation":"FunctionTool.real_fn is a property returning self._real_fn; it raises ValueError when _real_fn was never set. Given __init__ enforces fn or async_fn, this only fires on improperly initialized objects: instances created via __new__ without __init__ (e.g. pickle/deserialization paths, copies), or subclasses/monkeypatching that bypass or reset __init__.","triggerScenarios":"Accessing tool.real_fn on a FunctionTool reconstructed from pickle without running __init__; deep-copying or deserializing tools from agent dumps; a subclass overriding __init__ and forgetting to set _real_fn; test doubles calling FunctionTool.__new__.","commonSituations":"Persisting/loading agents that contain FunctionTools across processes; multiprocessing workers that unpickle tools; mock frameworks creating allocation-only instances; refactors splitting initialization from construction.","solutions":["Construct FunctionTool properly through its constructor so _real_fn is set.","For pickling, implement __getstate__/__setstate__ (or reduce) that re-runs construction with the original fn reference rather than raw state.","Access the underlying callable defensively: getattr(tool, '_real_fn', None) with a fallback to tool.fn.","In subclasses, ensure super().__init__(fn=..., metadata=...) is invoked."],"exampleFix":"# before\ntool = pickle.loads(payload)  # instance whose __init__ never ran\nfn = tool.real_fn  # ValueError: Real function is not set!\n\n# after\nclass PickleableFunctionTool(FunctionTool):\n    def __getstate__(self):\n        return {\"fn\": self._fn, \"metadata\": self._metadata}\n    def __setstate__(self, state):\n        self.__init__(fn=state[\"fn\"], metadata=state[\"metadata\"])\nfn = tool.real_fn  # ok","handlingStrategy":"type-guard","validationCode":"real = getattr(tool, '_real_fn', None)\nif real is None:\n    raise TypeError('tool not properly initialized; reconstruct via FunctionTool(...)')\nuse = real","typeGuard":"def tool_has_real_fn(tool) -> bool:\n    return getattr(tool, \"_real_fn\", None) is not None","tryCatchPattern":"try:\n    fn = tool.real_fn\nexcept ValueError:\n    fn = tool.fn  # sync fallback or re-init the tool","preventionTips":["Implement __getstate__/__setstate__ on pickled FunctionTool subclasses to re-run __init__.","Avoid creating tools via __new__ or mocks that skip initialization.","Call super().__init__ in subclasses."],"tags":["tools","deserialization","pickle","llama-index"],"backgroundTag":null,"analyzedSha":"afd0fef371831f9bda13e5af7167cf4e981278ab","analyzedAt":"2026-08-15T05:42:58.429Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}