{"record":{"id":"af851c2b09379e68","repo":"alibaba/spring-ai-alibaba","slug":"reactagent-tool-names-cannot-be-empty","errorCode":null,"errorMessage":"ReactAgent tool names cannot be empty","messagePattern":"ReactAgent tool names cannot be empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/generator/agent/impl/ReactAgentProvider.java","lineNumber":173,"sourceCode":"\t\t\t.var(var)\n\t\t\t.resolver(hasResolver);\n\t}\n\n\t@Override\n\tprotected void validateSpecific(Map<String, Object> root) {\n\t\t// ReactAgent 必须有 model 配置\n\t\tMap<String, Object> handle = requireHandle(root);\n\n\t\tif (handle.get(\"model\") == null) {\n\t\t\tthrow new IllegalArgumentException(\"ReactAgent requires model configuration in handle\");\n\t\t}\n\n\t\t// 如果有 tools，检查相关配置\n\t\tif (handle.get(\"tools\") instanceof List<?> tools && !tools.isEmpty()) {\n\t\t\t// 检查 tools 是否为空字符串\n\t\t\tfor (Object tool : tools) {\n\t\t\t\tif (tool instanceof String s && s.trim().isEmpty()) {\n\t\t\t\t\tthrow new IllegalArgumentException(\"ReactAgent tool names cannot be empty\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 检查 max_iterations 如果存在，必须是正数\n\t\tObject maxIterations = handle.get(\"max_iterations\");\n\t\tif (maxIterations != null) {\n\t\t\trequirePositiveNumber(maxIterations, \"max_iterations\", 1);\n\t\t}\n\t}\n\n}\n","sourceCodeStart":155,"sourceCodeEnd":186,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/generator/agent/impl/ReactAgentProvider.java#L155-L186","documentation":"ReactAgentProvider.validateSpecific validates a ReactAgent node definition during project generation. If the agent declares a tools list and any entry is a string that is empty or whitespace-only, generation is aborted with this IllegalArgumentException. It exists to prevent generating an agent whose tool bindings contain meaningless empty names.","triggerScenarios":"Calling generate() on a project whose metadata contains a ReactAgent node with a 'tools' array (non-empty) where at least one element is a String whose trim() is empty, e.g. tools: [\"\", \" \", \"search\"].","commonSituations":"A user left a blank row in the tools UI field; YAML/JSON config authored by hand with an empty quoted string; a form submitted without selecting tools but the list already contains a placeholder empty entry.","solutions":["Open the agent node config and remove or fill in every empty string entry in the tools list.","Trim and filter the tools list client-side before saving the workflow definition.","Wrap generation in a try-catch for IllegalArgumentException and surface a per-field validation message for the tools input."],"exampleFix":"// before\ntools: [\"\", \"web-search\"]\n// after\ntools: [\"web-search\"]  // remove empty names; validate before submit","handlingStrategy":"validation","validationCode":"List<String> tools = (List<String>) handle.getOrDefault(\"tools\", List.of());\nif (tools.stream().anyMatch(t -> t == null || t.trim().isEmpty()))\n    throw new IllegalArgumentException(\"ReactAgent has empty tool names\");","typeGuard":"boolean validTools(Object tools) { return !(tools instanceof List<?> l) || l.stream().allMatch(t -> t instanceof String s && !s.trim().isEmpty()); }","tryCatchPattern":"try { generator.generate(...); } catch (IllegalArgumentException e) { log.error(\"Invalid agent config: {}\", e.getMessage()); }","preventionTips":["Filter empty strings from tools lists before saving agent configs","Validate tool name inputs in the UI on submit","Add a schema check rejecting blank strings in tools arrays"],"tags":["validation","agent-config","empty-string"],"backgroundTag":"empty-required-field","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}