{"record":{"id":"8381c760776fe75e","repo":"microsoft/autogen","slug":"invalid-name-name-only-letters-numbers-a","errorCode":null,"errorMessage":"Invalid name: {name}. Only letters, numbers, '_' and '-' are allowed.","messagePattern":"Invalid name: (.+?)\\. Only letters, numbers, '_' and '-' are allowed\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/models/anthropic/_anthropic_client.py","lineNumber":413,"sourceCode":"    def _to_config(self) -> AnthropicClientConfigurationConfigModel:\n        copied_config = self._raw_config.copy()\n        return AnthropicClientConfigurationConfigModel(**copied_config)\n\n    @classmethod\n    def _from_config(cls, config: AnthropicClientConfigurationConfigModel) -> Self:\n        copied_config = config.model_copy().model_dump(exclude_none=True)\n        return cls(**copied_config)\n    Normalize names by replacing invalid characters with underscore.\n    \"\"\"\n    return re.sub(r\"[^a-zA-Z0-9_-]\", \"_\", name)[:64]\n\n\ndef assert_valid_name(name: str) -> str:\n    \"\"\"\n    Ensure that configured names are valid, raises ValueError if not.\n    \"\"\"\n    if not re.match(r\"^[a-zA-Z0-9_-]+$\", name):\n        raise ValueError(f\"Invalid name: {name}. Only letters, numbers, '_' and '-' are allowed.\")\n    if len(name) > 64:\n        raise ValueError(f\"Invalid name: {name}. Name must be less than 64 characters.\")\n    return name\n\n\ndef normalize_stop_reason(stop_reason: str | None) -> FinishReasons:\n    if stop_reason is None:\n        return \"unknown\"\n\n    # Convert to lowercase for comparison\n    stop_reason = stop_reason.lower()\n\n    # Map Anthropic stop reasons to standard reasons\n    KNOWN_STOP_MAPPINGS: Dict[str, FinishReasons] = {\n        \"end_turn\": \"stop\",\n        \"max_tokens\": \"length\",\n        \"stop_sequence\": \"stop\",\n        \"tool_use\": \"function_calls\",","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/models/anthropic/_anthropic_client.py#L395-L431","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rename the tool to letters/digits/underscore/hyphen, <= 64 chars: 'MyClass_my_method' instead of 'MyClass.my_method'.","For generated names, apply normalize_name(name) (same module) before creating the tool.","Add a startup validation pass over all tool schemas so offending names fail loudly before deployment."],"exampleFix":"# before\ntool = FunctionTool(get_weather, name='tools.get_weather', description=...)  # ValueError on register\n\n# after\nimport re\nname = re.sub(r'[^a-zA-Z0-9_-]', '_', 'tools.get_weather')[:64]  # -> 'tools_get_weather'\ntool = FunctionTool(get_weather, name=name, description=...)","handlingStrategy":"validation","validationCode":"import re\n\ndef valid_tool_name(name: str) -> bool:\n    return bool(re.match(r'^[a-zA-Z0-9_-]+$', name)) and len(name) <= 64\n\n# or sanitize: re.sub(r'[^a-zA-Z0-9_-]', '_', name)[:64]","typeGuard":"def is_valid_anthropic_name(name: str) -> bool:\n    return bool(re.fullmatch(r'[a-zA-Z0-9_-]{1,64}', name))","tryCatchPattern":"try:\n    client.register_tool(tool)\nexcept ValueError as e:\n    if 'Invalid name' in str(e):\n        tool.schema['name'] = re.sub(r'[^a-zA-Z0-9_-]', '_', tool.schema['name'])[:64]\n        client.register_tool(tool)\n    else:\n        raise","preventionTips":["Run assert_valid_name (or the regex) over all tool names at startup","Auto-sanitize generated names with normalize_name before registration","Avoid dots/spaces/unicode in names derived from methods or operationIds"],"tags":["anthropic","tool-names","validation","llm-client"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}