run-llama/llama_index · error · ValueError
spec_functions must be of type: List[Union[str, Tuple[str, s
Error message
spec_functions must be of type: List[Union[str, Tuple[str, str]]]
What it means
BaseToolSpec.to_tool_list() validates each entry of spec_functions. Entries must be a plain string (function name) or a tuple of exactly two strings (sync function name, async function name). Anything else - ints, 3-tuples, single-element tuples, lists - raises this ValueError before any tool is built.
Source
Thrown at llama-index-core/llama_index/core/tools/tool_spec/base.py:95
if isinstance(func_spec, str):
func = getattr(self, func_spec)
if inspect.iscoroutinefunction(func):
func_async = func
else:
func_sync = func
metadata = func_to_metadata_mapping.get(func_spec, None)
if metadata is None:
metadata = self.get_metadata_from_fn_name(func_spec)
elif isinstance(func_spec, tuple) and len(func_spec) == 2:
func_sync = getattr(self, func_spec[0])
func_async = getattr(self, func_spec[1])
metadata = func_to_metadata_mapping.get(func_spec[0], None)
if metadata is None:
metadata = func_to_metadata_mapping.get(func_spec[1], None)
if metadata is None:
metadata = self.get_metadata_from_fn_name(func_spec[0])
else:
raise ValueError(
"spec_functions must be of type: List[Union[str, Tuple[str, str]]]"
)
tool = FunctionTool.from_defaults(
fn=func_sync,
async_fn=func_async,
tool_metadata=metadata,
)
tool_list.append(tool)
return tool_list
async def to_tool_list_async(
self,
spec_functions: Optional[List[SPEC_FUNCTION_TYPE]] = None,
func_to_metadata_mapping: Optional[Dict[str, ToolMetadata]] = None,
) -> List[FunctionTool]:
"""Asynchronously convert a tool spec to a list of tools."""
return await asyncio.to_thread(View on GitHub (pinned to afd0fef371)
Solutions
- Normalize every entry to either 'fn_name' or ('sync_fn_name', 'async_fn_name').
- If you have function objects, use their __name__: spec_functions=[fn.__name__ for fn in fns].
- Check for trailing commas that turn a string into a 1-tuple: ('query',) is invalid.
Example fix
# before
spec_functions = ["search", ("sync_read",), "summarize"]
tools = spec.to_tool_list(spec_functions=spec_functions)
# after
spec_functions = ["search", ("sync_read", "async_read"), "summarize"]
tools = spec.to_tool_list(spec_functions=spec_functions) Defensive patterns
Strategy: validation
Validate before calling
def validate_spec_functions(spec_functions):
for entry in spec_functions:
if isinstance(entry, str):
continue
if isinstance(entry, tuple) and len(entry) == 2 and all(isinstance(x, str) for x in entry):
continue
raise TypeError(f'Bad spec_functions entry: {entry!r}; use str or (sync, async) tuple')
return spec_functions Type guard
from typing import Union, Tuple, List
def is_valid_spec_functions(value) -> bool:
return isinstance(value, list) and all(
isinstance(e, str) or (isinstance(e, tuple) and len(e) == 2 and all(isinstance(p, str) for p in e))
for e in value
) Try / catch
try:
tools = spec.to_tool_list(spec_functions=spec_functions)
except ValueError as e:
if 'spec_functions' in str(e):
raise ValueError(f'Fix spec_functions shape: {spec_functions}') from e
raise Prevention
- Run a shape assertion on spec_functions before calling to_tool_list.
- Generate entries from function objects via __name__ instead of hand-writing tuples.
- Beware trailing commas: ('fn',) is a 1-tuple and will fail.
When it happens
Trigger: Calling to_tool_list() on a tool spec subclass while passing spec_functions=[...] (or overriding/spec_functions containing) entries like ('fn',), ['fn'], ('sync','async','extra'), or a non-string value.
Common situations: Hand-writing a custom ToolSpec and mistyping spec_functions; passing a list of function objects instead of names; copying an example that used 3-tuples from an older API.
Related errors
- Tool name cannot be None
- Cannot provide both content and blocks.
- Invalid additional field info: {field_info}. Must be a tuple
- Invalid data URL format: missing comma separator
- No valid source provided to resolve binary data!
AI-assisted analysis of run-llama/llama_index@afd0fef371 (2026-08-15).
Data as JSON: /api/errors/db308ad34b57aff1.
Report an issue: GitHub.