{"record":{"id":"79c6cf8a9a643507","repo":"alibaba/spring-ai-alibaba","slug":"maxcachedthreads-must-be-greater-than-or-equal-to","errorCode":null,"errorMessage":"maxCachedThreads must be greater than or equal to 0","messagePattern":"maxCachedThreads must be greater than or equal to 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/common/LatestCheckpointCache.java","lineNumber":42,"sourceCode":"\n/**\n * A bounded LRU cache that stores the latest checkpoint for each thread.\n */\npublic final class LatestCheckpointCache {\n\n\tprivate final int maxCachedThreads;\n\n\tprivate final Map<String, Checkpoint> checkpoints;\n\n\t/**\n\t * Creates a latest-checkpoint cache with an LRU thread limit.\n\t *\n\t * @param maxCachedThreads maximum number of thread entries to keep, or 0 to\n\t * disable caching\n\t */\n\tpublic LatestCheckpointCache(int maxCachedThreads) {\n\t\tif (maxCachedThreads < 0) {\n\t\t\tthrow new IllegalArgumentException(\"maxCachedThreads must be greater than or equal to 0\");\n\t\t}\n\t\tthis.maxCachedThreads = maxCachedThreads;\n\t\tthis.checkpoints = createCache(maxCachedThreads);\n\t}\n\n\t/**\n\t * Gets the cached latest checkpoint for a thread.\n\t *\n\t * @param threadId thread name/id used by the owning saver\n\t * @return cached checkpoint when caching is enabled and the thread is present\n\t */\n\tpublic synchronized Optional<Checkpoint> get(String threadId) {\n\t\tif (maxCachedThreads == 0) {\n\t\t\treturn Optional.empty();\n\t\t}\n\t\treturn Optional.ofNullable(checkpoints.get(threadId));\n\t}\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/common/LatestCheckpointCache.java#L24-L60","documentation":"LatestCheckpointCache is a per-thread LRU cache of the latest checkpoints. maxCachedThreads counts thread entries; 0 disables caching. A negative value is rejected in the constructor with IllegalArgumentException.","triggerScenarios":"new LatestCheckpointCache(-1) or any negative capacity, directly or via a saver builder passing a negative cache-size setting.","commonSituations":"Misreading the semantics of the parameter (thinking it's a timeout or byte size) or computing it from config where a negative/invalid default slipped in.","solutions":["Pass 0 to disable caching, or a positive thread-count","Clamp or validate the configured value before constructing the cache","Fix upstream config parsing that produced a negative number"],"exampleFix":"// before\nnew LatestCheckpointCache(config.getCacheSize()); // -1 from config\n// after\nint size = Math.max(0, config.getCacheSize());\nnew LatestCheckpointCache(size);","handlingStrategy":"validation","validationCode":"if (maxCachedThreads < 0) throw new IllegalArgumentException(\"maxCachedThreads must be >= 0\");","typeGuard":"Integer sanitize(Integer v) { return v == null || v < 0 ? 0 : v; }","tryCatchPattern":"try { new LatestCheckpointCache(n); } catch (IllegalArgumentException e) { /* fall back to 0 */ }","preventionTips":["Clamp config-sourced cache sizes with Math.max(0, v)","Remember 0 disables caching (valid value)","Add builder-level sanity tests"],"tags":["checkpoint","cache","validation"],"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-14T11:17:12.474Z"}