{"record":{"id":"76e32da2608491fb","repo":"spring-projects/spring-ai","slug":"either-ttl-or-expire-time-must-be-set-for-update","errorCode":null,"errorMessage":"Either TTL or expire time must be set for update","messagePattern":"Either TTL or expire time must be set for update","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/cache/CachedContentUpdateRequest.java","lineNumber":82,"sourceCode":"\n\t\t@Nullable private Instant expireTime;\n\n\t\tprivate Builder() {\n\t\t}\n\n\t\tpublic Builder ttl(Duration ttl) {\n\t\t\tthis.ttl = ttl;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic Builder expireTime(Instant expireTime) {\n\t\t\tthis.expireTime = expireTime;\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic CachedContentUpdateRequest build() {\n\t\t\tif (this.ttl == null && this.expireTime == null) {\n\t\t\t\tthrow new IllegalArgumentException(\"Either TTL or expire time must be set for update\");\n\t\t\t}\n\t\t\treturn new CachedContentUpdateRequest(this);\n\t\t}\n\n\t}\n\n}\n","sourceCodeStart":64,"sourceCodeEnd":90,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/cache/CachedContentUpdateRequest.java#L64-L90","documentation":"CachedContentUpdateRequest.build() enforces that an update to cached content changes its expiration: at least one of ttl or expireTime must be set, otherwise IllegalArgumentException is thrown. Gemini's cachedContent update API requires an expiration change.","triggerScenarios":"Calling builder.build() with neither .ttl(...) nor .expireTime(...) set, then submitting the update for a cached content resource.","commonSituations":"Copying update-request code that previously set expiration; conditionally setting expiration values where both branches evaluated to null; intending to update other fields but the API only supports expiration updates.","solutions":["Set a TTL, e.g. builder.ttl(Duration.ofHours(2)).build().","Or set an absolute expireTime, e.g. builder.expireTime(Instant.now().plus(Duration.ofDays(1))).build().","If no expiration change is desired, skip the update call entirely (the API only supports updating expiration).","Validate that at least one expiration field is non-null before building in your service layer."],"exampleFix":"// before\nnew CachedContentUpdateRequest.Builder().build(); // throws\n// after\nnew CachedContentUpdateRequest.Builder().ttl(Duration.ofHours(2)).build();","handlingStrategy":"validation","validationCode":"if (ttl == null && expireTime == null) {\n    throw new IllegalStateException(\"set ttl or expireTime before building CachedContentUpdateRequest\");\n}","typeGuard":null,"tryCatchPattern":"try { req.build(); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"TTL or expire time\")) setDefaultTtl(); else throw e; }","preventionTips":["Always chain .ttl() or .expireTime() in builder helpers","Remember cached-content updates only change expiration","Unit-test cache update builders for required fields"],"tags":["cache","gemini","validation","required-field"],"backgroundTag":"missing-required-argument","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}