run-llama/llama_index · error · ValueError

Tool {tool.metadata.name} requires context. CodeActAgent onl

Error message

Tool {tool.metadata.name} requires context. CodeActAgent only supports tools that do not require context.

What it means

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__.

Source

Thrown at llama-index-core/llama_index/core/agent/workflow/codeact_agent.py:137

            llm=llm,
            code_act_system_prompt=code_act_system_prompt,
            code_execute_fn=code_execute_fn,
            streaming=streaming,
        )

    def _get_tool_fns(self, tools: Sequence[BaseTool]) -> List[Callable]:
        """Get the tool functions while validating that they are valid tools for the CodeActAgent."""
        callables = []
        for tool in tools:
            if (
                tool.metadata.name == "handoff"
                or tool.metadata.name == EXECUTE_TOOL_NAME
            ):
                continue

            if isinstance(tool, FunctionTool):
                if tool.requires_context:
                    raise ValueError(
                        f"Tool {tool.metadata.name} requires context. "
                        "CodeActAgent only supports tools that do not require context."
                    )

                callables.append(tool.real_fn)
            else:
                raise ValueError(
                    f"Tool {tool.metadata.name} is not a FunctionTool. "
                    "CodeActAgent only supports Functions and FunctionTools."
                )

        return callables

    def _extract_code_from_response(self, response_text: str) -> Optional[str]:
        """
        Extract code from the LLM response using XML-style <execute> tags.

        Args:

View on GitHub (pinned to afd0fef371)

Solutions

  1. Construct FunctionTool properly through its constructor so _real_fn is set.
  2. For pickling, implement __getstate__/__setstate__ (or reduce) that re-runs construction with the original fn reference rather than raw state.
  3. Access the underlying callable defensively: getattr(tool, '_real_fn', None) with a fallback to tool.fn.
  4. In subclasses, ensure super().__init__(fn=..., metadata=...) is invoked.

Example fix

# before
tool = pickle.loads(payload)  # instance whose __init__ never ran
fn = tool.real_fn  # ValueError: Real function is not set!

# after
class PickleableFunctionTool(FunctionTool):
    def __getstate__(self):
        return {"fn": self._fn, "metadata": self._metadata}
    def __setstate__(self, state):
        self.__init__(fn=state["fn"], metadata=state["metadata"])
fn = tool.real_fn  # ok
Defensive patterns

Strategy: type-guard

Validate before calling

real = getattr(tool, '_real_fn', None)
if real is None:
    raise TypeError('tool not properly initialized; reconstruct via FunctionTool(...)')
use = real

Type guard

def tool_has_real_fn(tool) -> bool:
    return getattr(tool, "_real_fn", None) is not None

Try / catch

try:
    fn = tool.real_fn
except ValueError:
    fn = tool.fn  # sync fallback or re-init the tool

Prevention

When it happens

Trigger: 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__.

Common situations: Persisting/loading agents that contain FunctionTools across processes; multiprocessing workers that unpickle tools; mock frameworks creating allocation-only instances; refactors splitting initialization from construction.

Related errors


AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15). Data as JSON: /api/errors/f3bd0ed493c981d9. Report an issue: GitHub.