github/copilot-sdk · error · ValueError
invalid tool name: must not be empty
Error message
invalid {kind} tool name: must not be empty What it means
Tool names registered via ToolSet.add_builtin/add_custom/add_mcp must be non-empty strings. An empty name cannot match any tool and would produce ambiguous filter entries, so _validate_tool_name raises immediately. The wildcard "*" is allowed but only as a full string, not empty.
Solutions
- Pass a non-empty tool name string to the add_* method
- If the name comes from parsing, verify the segment index (e.g. name.split(':')[-1]) before registering
- Fail fast at config load time: assert the tool name is non-empty before constructing a ToolSet
- Use ToolSet().add_builtin('*') if the intent was to match all tools of a source
Example fix
// before
prefix, _, tool = spec.partition(':') # tool == '' when spec == 'builtin:'
toolset.add_builtin(tool)
// after
prefix, _, tool = spec.partition(':')
if not tool:
raise ValueError(f"missing tool name in {spec!r}")
toolset.add_builtin(tool) Defensive patterns
Strategy: validation
Validate before calling
if not isinstance(name, str) or not name:
raise ValueError(f"{kind} tool name must be a non-empty string") Type guard
def is_valid_tool_name(name) -> bool:
return isinstance(name, str) and bool(name) Try / catch
try:
toolset.add_builtin(name)
except ValueError as e:
logger.error(f"bad tool name {name!r}: {e}")
raise Prevention
- Assert tool names are non-empty at config load time
- Check indices when splitting prefixed identifiers like 'mcp:server:tool'
- Strip whitespace and source prefixes before registering tool names
- Favor ToolSet builder methods over hand-assembled name strings
When it happens
Trigger: Calling add_builtin(''), add_custom(''), or add_mcp('') — or passing a name that evaluates falsy (e.g. an empty string from an unparseable 'builtin:' prefix or a split() result) — into _validate_tool_name.
Common situations: Parsing tool identifiers like 'mcp:server:tool' with split(':') and picking the wrong segment; building names from env vars or config keys that are unset; string concatenation producing an empty suffix.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- invalid tool name : tool names must match…
- invalid entry '*': there is no bare wildcard. Use…
- must not be null or blank
- Invalid entry '*': there is no bare wildcard. Use `new…
- CopilotClient is in Mode = CopilotClientMode.Empty but the…
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/44cadde05e46d5f0.
Report an issue: GitHub.
Appendix: source
Thrown at python/copilot/_mode.py:26
"""
from __future__ import annotations
import re
from collections.abc import Iterable
from typing import TYPE_CHECKING, Any, Literal
if TYPE_CHECKING:
from .session import MemoryConfiguration
CopilotClientMode = Literal["copilot-cli", "empty"]
_TOOL_NAME_REGEX = re.compile(r"^[a-zA-Z0-9_-]+$")
def _validate_tool_name(kind: str, name: str) -> None:
if not name:
raise ValueError(f"invalid {kind} tool name: must not be empty")
if name == "*":
return
if not _TOOL_NAME_REGEX.match(name):
raise ValueError(
f"invalid {kind} tool name {name!r}: tool names must match "
r"/^[a-zA-Z0-9_-]+$/ or be the wildcard '*'"
)
class ToolSet:
"""Builder for source-qualified tool filter patterns.
``ToolSet`` accumulates entries like ``builtin:bash``, ``mcp:*``, or
``custom:my_tool`` for use in
:class:`CopilotClient.create_session`'s ``available_tools`` /
``excluded_tools`` parameters.
Tool classification (``builtin``/``mcp``/``custom``) is determined by theView on GitHub (pinned to cd8cf15dc3)