{"record":{"id":"6e8b80c4066a93fd","repo":"spring-projects/spring-ai","slug":"tool-name-toolname-may-not-be-compatible-with","errorCode":null,"errorMessage":"Tool name '${toolName}' may not be compatible with some LLMs (e.g., OpenAI). Consider using only alphanumeric characters, underscores, hyphens, and dots.","messagePattern":"Tool name '(.+?)' may not be compatible with some LLMs \\(e\\.g\\., OpenAI\\)\\. Consider using only alphanumeric characters, underscores, hyphens, and dots\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolUtils.java","lineNumber":131,"sourceCode":"\t\t\t.filter(entry -> entry.getValue() > 1)\n\t\t\t.map(Map.Entry::getKey)\n\t\t\t.toList();\n\t}\n\n\tpublic static List<String> getDuplicateToolNames(ToolCallback... toolCallbacks) {\n\t\tAssert.notNull(toolCallbacks, \"toolCallbacks cannot be null\");\n\t\treturn getDuplicateToolNames(Arrays.asList(toolCallbacks));\n\t}\n\n\t/**\n\t * Validates that a tool name follows recommended naming conventions. Logs a warning\n\t * if the tool name contains characters that may not be compatible with some LLMs.\n\t * @param toolName the tool name to validate\n\t */\n\tprivate static void validateToolName(String toolName) {\n\t\tAssert.hasText(toolName, \"Tool name cannot be null or empty\");\n\t\tif (logger.isWarnEnabled() && !RECOMMENDED_NAME_PATTERN.matcher(toolName).matches()) {\n\t\t\tlogger.warn(\"Tool name '\" + toolName + \"' may not be compatible with some LLMs (e.g., OpenAI). \"\n\t\t\t\t\t+ \"Consider using only alphanumeric characters, underscores, hyphens, and dots.\");\n\t\t}\n\t}\n\n}\n","sourceCodeStart":113,"sourceCodeEnd":137,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-model/src/main/java/org/springframework/ai/tool/support/ToolUtils.java#L113-L137","documentation":"ToolUtils.validateToolName logs a warning when a tool name does not match the recommended pattern (alphanumeric, underscore, hyphen, dot). Some LLM providers such as OpenAI enforce strict name characters, and names outside this set may be rejected or mangled by the model. The name is still used; only a warning is emitted after a basic hasText assertion.","triggerScenarios":"Any tool definition whose name is passed through getToolName -> validateToolName contains characters like spaces, '@', '(', ')', non-ASCII letters, or is empty (empty throws IllegalArgumentException from Assert.hasText).","commonSituations":"Auto-generating tool names from method signatures or FQCNs (dots are fine but spaces/parens are not); exposing Spring bean method names with special chars; localizing tool names.","solutions":["Rename the tool to use only [a-zA-Z0-9_.-], e.g. convert camelCase or spaced names to snake_case.","Set an explicit tool name instead of deriving it from class/method names (e.g. @Tool(name = \"get_weather\")).","If names come from a registry, sanitize them before registration (replace invalid chars with '_')."],"exampleFix":"// before\n@Tool(name = \"Weather Lookup (live)\")\nString weather(String city) { ... }\n\n// after\n@Tool(name = \"weather_lookup_live\")\nString weather(String city) { ... }","handlingStrategy":"validation","validationCode":"private static final Pattern OK = Pattern.compile(\"[a-zA-Z0-9_.-]+\");\nif (!OK.matcher(toolName).matches()) throw new IllegalArgumentException(\"Invalid tool name: \" + toolName);","typeGuard":"boolean isValidToolName(String n) { return n != null && n.matches(\"[a-zA-Z0-9_.-]+\"); }","tryCatchPattern":null,"preventionTips":["Always set explicit names via @Tool(name=...) using [a-zA-Z0-9_.-] only.","Sanitize auto-generated names (replace invalid chars with '_').","Avoid deriving names from localized text or human-readable labels.","Add a startup assertion that every registered tool name matches the recommended pattern."],"tags":["tool-calling","naming","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}