{"record":{"id":"f107231fe0c35cd7","repo":"quarkusio/quarkus","slug":"timestamp-must-not-be-null-f10723","errorCode":null,"errorMessage":"`timestamp` must not be `null`","messagePattern":"`timestamp` must not be `null`","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/string/SetArgs.java","lineNumber":73,"sourceCode":"     * Sets the expiration time\n     *\n     * @param timestamp the timestamp\n     * @return the current {@code GetExArgs}\n     */\n    public SetArgs exAt(long timestamp) {\n        this.exAt = timestamp;\n        return this;\n    }\n\n    /**\n     * Sets the expiration time\n     *\n     * @param timestamp the timestamp type: posix time in seconds.\n     * @return the current {@code GetExArgs}\n     */\n    public SetArgs exAt(Instant timestamp) {\n        if (timestamp == null) {\n            throw new IllegalArgumentException(\"`timestamp` must not be `null`\");\n        }\n        exAt(timestamp.toEpochMilli() / 1000);\n        return this;\n    }\n\n    /**\n     * Set the specified expire time, in milliseconds.\n     *\n     * @param timeout expire time in milliseconds.\n     * @return the current {@code GetExArgs}\n     */\n    public SetArgs px(long timeout) {\n        if (timeout < 0) {\n            throw new IllegalArgumentException(\"`timeout` must be positive\");\n        }\n        this.px = timeout;\n        return this;\n    }","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/string/SetArgs.java#L55-L91","documentation":"SetArgs.exAt(Instant) sets the EXAT (unix expiry in seconds) option for a Redis SET command and rejects a null Instant. The client validates eagerly so the error surfaces at the call site with a clear message instead of a malformed Redis command. Null has no valid epoch representation.","triggerScenarios":"Calling SetArgs exAt(null), typically from a nullable Instant field (e.g. 'expiresAt' column null for never-expiring records) passed without a check.","commonSituations":"Mapping an entity whose optional expiration timestamp is null into cache-set logic; or refactoring code where the timestamp became optional but the args-building code was not updated.","solutions":["Skip exAt() when the timestamp is null: build SetArgs conditionally","Default the Instant, e.g. Instant.now().plus(configuredTtl), when absence should mean a default expiry","Use ex()/px() duration-based variants when an absolute timestamp is not actually required"],"exampleFix":"// before\nInstant expiresAt = record.getExpiresAt(); // may be null\nSetArgs args = SetArgs.args().exAt(expiresAt); // throws\n\n// after\nInstant expiresAt = record.getExpiresAt();\nSetArgs args = expiresAt != null\n    ? SetArgs.args().exAt(expiresAt)\n    : SetArgs.args();","handlingStrategy":"validation","validationCode":"if (expiresAt == null) {\n    throw new IllegalStateException(\"expiresAt is required for exAt; use ex()/px() for relative TTL\");\n}\nSetArgs.args().exAt(expiresAt);","typeGuard":"boolean hasExpiry(Instant ts) {\n    return ts != null && ts.isAfter(Instant.now());\n}","tryCatchPattern":"try {\n    args.exAt(timestamp);\n} catch (IllegalArgumentException e) {\n    if (!e.getMessage().contains(\"`timestamp` must not be `null`\")) throw e;\n    args = SetArgs.args(); // proceed without EXAT\n}","preventionTips":["Model optional expiries as Optional<Instant> and branch before building args","Prefer relative ex()/px() when the value is derived from 'now + ttl' anyway","Unit-test the null-timestamp path of cache-write code"],"tags":["redis","null-argument","illegal-argument","validation"],"backgroundTag":"null-required-argument","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}