{"record":{"id":"c293aa8a9d505b73","repo":"alibaba/spring-ai-alibaba","slug":"ttlunit-cannot-be-null","errorCode":null,"errorMessage":"ttlUnit cannot be null","messagePattern":"ttlUnit cannot be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/redis/RedisSaver.java","lineNumber":471,"sourceCode":"\t\t\tthis.stateSerializer = stateSerializer;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Sets the time-to-live (TTL) for all Redis keys managed by RedisSaver.\n\t\t * When set, checkpoint data, thread metadata, and reverse mappings will\n\t\t * automatically expire after the specified duration.\n\t\t * <p>\n\t\t * Default is -1 (no expiration), which preserves backward compatibility.\n\t\t *\n\t\t * @param ttl the time-to-live value, must be positive; -1 means no expiration\n\t\t * @param ttlUnit the time unit for ttl, must not be null\n\t\t * @return this builder\n\t\t * @throws IllegalArgumentException if ttlUnit is null or ttl is 0 or less than -1\n\t\t */\n\t\tpublic Builder ttl(long ttl, TimeUnit ttlUnit) {\n\t\t\tif (ttlUnit == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"ttlUnit cannot be null\");\n\t\t\t}\n\t\t\tif (ttl == 0 || ttl < -1) {\n\t\t\t\tthrow new IllegalArgumentException(\"ttl must be positive or -1 (no expiration), got: \" + ttl);\n\t\t\t}\n\t\t\tthis.ttl = ttl;\n\t\t\tthis.ttlUnit = ttlUnit;\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Builds a new RedisSaver instance.\n\t\t * @return a new RedisSaver instance\n\t\t * @throws IllegalArgumentException if redisson or stateSerializer is null\n\t\t */\n\t\tpublic RedisSaver build() {\n\t\t\tif (redisson == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"redisson cannot be null\");\n\t\t\t}","sourceCodeStart":453,"sourceCodeEnd":489,"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/redis/RedisSaver.java#L453-L489","documentation":"RedisSaver.Builder.ttl(long, TimeUnit) validates that the time unit is provided. Passing null as ttlUnit throws IllegalArgumentException because a TTL without a unit is meaningless. The javadoc explicitly documents ttlUnit must not be null.","triggerScenarios":"new RedisSaver.Builder().ttl(60, null).build() — any builder chain that calls ttl() with a null TimeUnit, typically from a config mapping where the unit is read from properties and missing.","commonSituations":"Mapping YAML/properties config where only the numeric ttl is set and the unit key is absent; calling ttl(ttlValue, ttlUnitMap.get(\"unit\")) returning null; refactoring code that dropped the constant TimeUnit argument.","solutions":["Pass an explicit TimeUnit, e.g. ttl(60, TimeUnit.SECONDS).","If the unit comes from configuration, default it when absent (SECONDS) before calling the builder.","Validate the configured unit string with TimeUnit.valueOf(...) inside a null check before building the saver."],"exampleFix":"// before\nBuilder b = new RedisSaver.Builder().ttl(cfg.getTtl(), cfg.getUnit()); // getUnit() == null\n// after\nTimeUnit unit = cfg.getUnit() != null ? cfg.getUnit() : TimeUnit.SECONDS;\nBuilder b = new RedisSaver.Builder().ttl(cfg.getTtl(), unit);","handlingStrategy":"validation","validationCode":"if (ttlUnit == null) {\n    throw new IllegalStateException(\"redis checkpoint ttlUnit must be configured (e.g. SECONDS)\");\n}\nsaverBuilder.ttl(ttl, ttlUnit);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass an explicit TimeUnit constant; never derive it from nullable config without a default.","Default missing unit config to TimeUnit.SECONDS at config-loading time.","Unit-test builder construction with the production config object."],"tags":["redis","builder","validation","null-argument"],"backgroundTag":"null-argument","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"}