{"record":{"id":"0e618ef7e8aa8546","repo":"alibaba/spring-ai-alibaba","slug":"maxretries-must-be-non-negative","errorCode":null,"errorMessage":"maxRetries must be non-negative","messagePattern":"maxRetries must be non-negative","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/WebFetchTool.java","lineNumber":449,"sourceCode":"\t\tpublic Builder maxContentLength(int maxContentLength) {\n\t\t\tif (maxContentLength <= 0) {\n\t\t\t\tthrow new IllegalArgumentException(\"maxContentLength must be positive\");\n\t\t\t}\n\t\t\tthis.maxContentLength = maxContentLength;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder maxCacheSize(int maxCacheSize) {\n\t\t\tif (maxCacheSize <= 0) {\n\t\t\t\tthrow new IllegalArgumentException(\"maxCacheSize must be positive\");\n\t\t\t}\n\t\t\tthis.maxCacheSize = maxCacheSize;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder maxRetries(int maxRetries) {\n\t\t\tif (maxRetries < 0) {\n\t\t\t\tthrow new IllegalArgumentException(\"maxRetries must be non-negative\");\n\t\t\t}\n\t\t\tthis.maxRetries = maxRetries;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder withName(String name) {\n\t\t\tthis.name = name;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder withDescription(String description) {\n\t\t\tthis.description = description;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic ToolCallback build() {\n\t\t\treturn FunctionToolCallback.builder(this.name, buildWebFetchTool())\n\t\t\t\t.description(this.description)","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/tools/WebFetchTool.java#L431-L467","documentation":"Builder.maxRetries validates that the retry count is non-negative; a negative value throws IllegalArgumentException. maxRetries is added to 1 to form the total attempt count, so negative values would produce zero or nonsensical attempt budgets (and a broken 'Failed after N attempts' message).","triggerScenarios":"Calling .maxRetries(-1) or any negative number on the WebFetchTool Builder, typically from a misparsed config value.","commonSituations":"Config property that defaults to -1 when absent; subtracting from a counter that can go below zero; typo in a properties file (maxRetries=-1 meant as 'disable').","solutions":["Pass 0 or a positive integer — 0 means a single attempt with no retries.","If loading from config, default missing values to 0 and reject negatives before building.","Omit the call to keep the default retry policy.","Clamp with Math.max(0, configuredValue) for dynamic values."],"exampleFix":"// before\n.maxRetries(-1)\n// after\n.maxRetries(2)","handlingStrategy":"validation","validationCode":"int retries = properties.maxRetries();\nif (retries < 0) {\n    throw new IllegalArgumentException(\"webfetch.max-retries must be >= 0, got \" + retries);\n}","typeGuard":"boolean isValidRetryCount(int v) { return v >= 0; }","tryCatchPattern":"try {\n    builder.maxRetries(retries);\n} catch (IllegalArgumentException e) {\n    log.warn(\"invalid maxRetries {}, falling back to 0\", retries);\n    builder.maxRetries(0);\n}","preventionTips":["Remember 0 retries = single attempt; never use negative values to disable retries","Normalize missing config values to 0 instead of -1 sentinels","Add builder-config unit tests that run with production property files"],"tags":["builder","validation","retry"],"backgroundTag":"invalid-argument-value","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}