{"record":{"id":"ccfca0c3843c14f0","repo":"alibaba/spring-ai-alibaba","slug":"fieldname-must-be-a-number","errorCode":null,"errorMessage":"${fieldName} must be a number","messagePattern":"(.+?) must be a number","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/AbstractAgentTypeProvider.java","lineNumber":106,"sourceCode":"\t\t\tthrow new IllegalArgumentException(\n\t\t\t\t\ttype() + \" requires at least \" + minCount + \" sub-agent(s), got: \" + subAgents.size());\n\t\t}\n\t\treturn subAgents;\n\t}\n\n\t/**\n\t * 校验数值字段\n\t * @param value 字段值\n\t * @param fieldName 字段名\n\t * @param minValue 最小值（包含）\n\t * @return 数值\n\t */\n\tprotected int requirePositiveNumber(Object value, String fieldName, int minValue) {\n\t\tif (value == null) {\n\t\t\tthrow new IllegalArgumentException(type() + \" requires '\" + fieldName + \"'\");\n\t\t}\n\t\tif (!(value instanceof Number)) {\n\t\t\tthrow new IllegalArgumentException(fieldName + \" must be a number\");\n\t\t}\n\t\tint num = ((Number) value).intValue();\n\t\tif (num < minValue) {\n\t\t\tthrow new IllegalArgumentException(fieldName + \" must be at least \" + minValue + \", got: \" + num);\n\t\t}\n\t\treturn num;\n\t}\n\n\t/**\n\t * 检查字符串是否为空\n\t */\n\tprotected boolean isBlank(String s) {\n\t\treturn s == null || s.trim().isEmpty();\n\t}\n\n\t/**\n\t * 检查是否有有效的输入键\n\t */","sourceCodeStart":88,"sourceCodeEnd":124,"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/AbstractAgentTypeProvider.java#L88-L124","documentation":"requirePositiveNumber() throws this when the field is present but is not a Number instance — e.g. a String \"5\", a Boolean, or a nested map. DSL values parsed from JSON/YAML can arrive as strings when quoted, and the provider does not coerce them.","triggerScenarios":"root.get(fieldName) returns a String like \"3\" (quoted number in YAML/JSON) or any non-numeric object, and validateSpecific() passes it to requirePositiveNumber().","commonSituations":"Quoting numbers in YAML (iterations: \"5\") which YAML parses as a string; JSON generated by a form UI that stringifies all values; reading config from an env var or DB column typed as text.","solutions":["Remove quotes so the value is a real number in JSON/YAML","Convert the string to a number in upstream code before passing the config to the generator","Check how the DSL file is parsed — YAML typers/loose parsers may help"],"exampleFix":"// before\n{\"type\": \"loop_agent\", \"name\": \"looper\", \"max_iterations\": \"5\"}\n// after\n{\"type\": \"loop_agent\", \"name\": \"looper\", \"max_iterations\": 5}","handlingStrategy":"type-guard","validationCode":"Object v = config.get(\"max_iterations\");\nif (!(v instanceof Number)) {\n    throw new IllegalArgumentException(\"max_iterations must be a JSON/YAML number, not \" + (v == null ? \"null\" : v.getClass().getSimpleName()));\n}","typeGuard":"static Integer asInt(Object v) {\n    return (v instanceof Number n) ? n.intValue() : null;\n}","tryCatchPattern":"try {\n    provider.validateDSL(root);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().endsWith(\"must be a number\")) {\n        // show the offending field and its quoted/string value\n    }\n}","preventionTips":["Never quote numeric values in YAML/JSON configs","Configure YAML parsers to keep native typing","Normalize form-UI output to emit real numbers, not strings"],"tags":["validation","type-mismatch","dsl"],"backgroundTag":"type-mismatch","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"}