github/copilot-sdk · error · ValueError

invalid entry '*': there is no bare wildcard. Use…

Error message

invalid {field} entry '*': there is no bare wildcard. Use ToolSet().add_builtin('*'), .add_mcp('*'), or .add_custom('*') to target a specific source.

What it means

When validating a tool filter list, a bare "*" entry is rejected because there is no cross-source wildcard — each source (builtin, mcp, custom) must be targeted explicitly. Use 'builtin:*', 'mcp:*', or 'custom:*' (or the equivalent ToolSet methods) to mean 'all tools of that source'.

Solutions

  1. Use ToolSet().add_builtin('*').add_mcp('*').add_custom('*') to allow all tools from every source
  2. Or pass a list of source-qualified wildcards: ['builtin:*', 'mcp:*', 'custom:*']
  3. Or list the specific tools you want instead of a global wildcard
  4. Fix config files that contain a bare '*' tool entry to use source-qualified values

Example fix

// before
client.create_session(available_tools=["*"])

// after
client.create_session(
    available_tools=ToolSet().add_builtin("*").add_mcp("*").add_custom("*").to_list()
)
Defensive patterns

Strategy: validation

Validate before calling

if any(entry == "*" for entry in (items or [])):
    raise ValueError('use "builtin:*", "mcp:*", or "custom:*" instead of bare "*"')

Type guard

def has_bare_wildcard(items) -> bool:
    return items is not None and "*" in items

Try / catch

try:
    session = client.create_session(available_tools=items)
except ValueError as e:
    if "bare wildcard" in str(e):
        items = ["builtin:*", "mcp:*", "custom:*"]
        session = client.create_session(available_tools=items)

Prevention

When it happens

Trigger: Calling create_session(available_tools=["*"]) or resume_session(tools=["*"]) — passing the wildcard without a source prefix into _validate_tool_filter_list.

Common situations: Developers assume "*" means 'all tools' (as it does inside ToolSet.add_builtin('*')) and use it directly in a plain list; config files contain tools: ["*"] intending to allow everything.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/852543d399bb476e. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/_mode.py:135

        return None
    if isinstance(value, ToolSet):
        return value.to_list()
    if isinstance(value, str):
        raise TypeError(
            "tool filter must be a ToolSet or list[str], not str. "
            'Pass a single-element list (e.g. ["builtin:bash"]) or a '
            "ToolSet (e.g. ToolSet().add_builtin('bash'))."
        )
    return list(value)


def _validate_tool_filter_list(field: str, items: list[str] | None) -> None:
    """Reject bare ``"*"`` entries (must use ``builtin:*``/``mcp:*``/``custom:*``)."""
    if items is None:
        return
    for entry in items:
        if entry == "*":
            raise ValueError(
                f"invalid {field} entry '*': there is no bare wildcard. "
                "Use ToolSet().add_builtin('*'), .add_mcp('*'), or "
                ".add_custom('*') to target a specific source."
            )


def _system_message_for_mode(
    mode: CopilotClientMode | None,
    supplied: Any,
) -> Any:
    """Apply empty-mode environment_context stripping to a system message dict.

    The caller passes the already-normalized wire payload (a ``dict`` with
    ``mode`` / ``content`` / ``sections``) or ``None``. The caller's value
    wins if it already specifies an ``environment_context`` override.
    """
    if mode != "empty":
        return supplied

View on GitHub (pinned to cd8cf15dc3)