microsoft/autogen · error · ValueError

Invalid name: {name}. Only letters, numbers, '_' and '-' are

Error message

Invalid name: {name}. Only letters, numbers, '_' and '-' are allowed.

What it means

Anthropic's API only accepts tool/function names matching ^[a-zA-Z0-9_-]+$ and at most 64 characters. assert_valid_name enforces this client-side and raises ValueError('Invalid name: ...') naming the offender — typically during register_tool / tool schema validation. normalize_name exists alongside it to auto-fix names by replacing bad characters with underscores and truncating to 64.

Source

Thrown at python/packages/autogen-ext/src/autogen_ext/models/anthropic/_anthropic_client.py:413

    def _to_config(self) -> AnthropicClientConfigurationConfigModel:
        copied_config = self._raw_config.copy()
        return AnthropicClientConfigurationConfigModel(**copied_config)

    @classmethod
    def _from_config(cls, config: AnthropicClientConfigurationConfigModel) -> Self:
        copied_config = config.model_copy().model_dump(exclude_none=True)
        return cls(**copied_config)
    Normalize names by replacing invalid characters with underscore.
    """
    return re.sub(r"[^a-zA-Z0-9_-]", "_", name)[:64]


def assert_valid_name(name: str) -> str:
    """
    Ensure that configured names are valid, raises ValueError if not.
    """
    if not re.match(r"^[a-zA-Z0-9_-]+$", name):
        raise ValueError(f"Invalid name: {name}. Only letters, numbers, '_' and '-' are allowed.")
    if len(name) > 64:
        raise ValueError(f"Invalid name: {name}. Name must be less than 64 characters.")
    return name


def normalize_stop_reason(stop_reason: str | None) -> FinishReasons:
    if stop_reason is None:
        return "unknown"

    # Convert to lowercase for comparison
    stop_reason = stop_reason.lower()

    # Map Anthropic stop reasons to standard reasons
    KNOWN_STOP_MAPPINGS: Dict[str, FinishReasons] = {
        "end_turn": "stop",
        "max_tokens": "length",
        "stop_sequence": "stop",
        "tool_use": "function_calls",

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Rename the tool to letters/digits/underscore/hyphen, <= 64 chars: 'MyClass_my_method' instead of 'MyClass.my_method'.
  2. For generated names, apply normalize_name(name) (same module) before creating the tool.
  3. Add a startup validation pass over all tool schemas so offending names fail loudly before deployment.

Example fix

# before
tool = FunctionTool(get_weather, name='tools.get_weather', description=...)  # ValueError on register

# after
import re
name = re.sub(r'[^a-zA-Z0-9_-]', '_', 'tools.get_weather')[:64]  # -> 'tools_get_weather'
tool = FunctionTool(get_weather, name=name, description=...)
Defensive patterns

Strategy: validation

Validate before calling

import re

def valid_tool_name(name: str) -> bool:
    return bool(re.match(r'^[a-zA-Z0-9_-]+$', name)) and len(name) <= 64

# or sanitize: re.sub(r'[^a-zA-Z0-9_-]', '_', name)[:64]

Type guard

def is_valid_anthropic_name(name: str) -> bool:
    return bool(re.fullmatch(r'[a-zA-Z0-9_-]{1,64}', name))

Try / catch

try:
    client.register_tool(tool)
except ValueError as e:
    if 'Invalid name' in str(e):
        tool.schema['name'] = re.sub(r'[^a-zA-Z0-9_-]', '_', tool.schema['name'])[:64]
        client.register_tool(tool)
    else:
        raise

Prevention

When it happens

Trigger: Registering a tool whose function name contains dots or spaces (e.g. 'tools.get_weather', 'get weather'), unicode characters, or exceeds 64 chars; tools generated from method paths ('MyClass.my_method'); FunctionTool with a name derived from user input.

Common situations: Auto-generating FunctionTool names from OpenAPI operationIds or class methods that contain '.'; porting tool sets from OpenAI (which historically allowed more characters); names with emoji/unicode from user-defined plugins.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/8381c760776fe75e. Report an issue: GitHub.