{"record":{"id":"94633054e3adc95a","repo":"quarkusio/quarkus","slug":"timeout-must-not-be-null-946330","errorCode":null,"errorMessage":"`timeout` must not be `null`","messagePattern":"`timeout` must not be `null`","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/value/SetArgs.java","lineNumber":46,"sourceCode":"     * @return the current {@code SetArgs}\n     */\n    public SetArgs ex(long timeout) {\n        if (timeout <= 0) {\n            throw new IllegalArgumentException(\"`timeout` must be positive\");\n        }\n        this.ex = timeout;\n        return this;\n    }\n\n    /**\n     * Set the expiration timeout, in seconds.\n     *\n     * @param timeout expiration timeout in seconds\n     * @return the current {@code SetArgs}\n     */\n    public SetArgs ex(Duration timeout) {\n        if (timeout == null) {\n            throw new IllegalArgumentException(\"`timeout` must not be `null`\");\n        }\n        return ex(timeout.toSeconds());\n    }\n\n    /**\n     * Set the expiration timestamp as a number of seconds since the Unix epoch.\n     *\n     * @param timestamp the timestamp\n     * @return the current {@code SetArgs}\n     */\n    public SetArgs exAt(long timestamp) {\n        this.exAt = timestamp;\n        return this;\n    }\n\n    /**\n     * Set the expiration timestamp as a number of seconds since the Unix epoch.\n     *","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/redis-client/runtime/src/main/java/io/quarkus/redis/datasource/value/SetArgs.java#L28-L64","documentation":"SetArgs.ex(Duration) converts the given Duration to seconds and delegates to ex(long). It rejects a null Duration with IllegalArgumentException up front so the failure is reported at the call site instead of as a NullPointerException deep inside duration conversion.","triggerScenarios":"Calling SetArgs.ex((Duration) null), typically when a nullable config property or optional TTL field is passed straight through without a null check.","commonSituations":"Optional @ConfigMapping Duration fields defaulting to null, DB/lookup results returning no TTL, or refactorings that made a previously defaulted value nullable.","solutions":["Check the Duration for null before calling ex(Duration), or pass Optional/ defaulted value.","Use a sentinel (e.g. skip the expiration args entirely) when no TTL is configured.","If a Duration of zero was intended, note that ex(Duration.ZERO) will also throw via ex(0) — use px() for sub-second TTLs."],"exampleFix":"// before\nSetArgs args = new SetArgs().ex(ttl); // ttl may be null\n// after\nSetArgs args = ttl != null ? new SetArgs().ex(ttl) : new SetArgs();","handlingStrategy":"type-guard","validationCode":"Objects.requireNonNull(ttl, \"ttl must not be null\");\nSetArgs args = new SetArgs().ex(ttl);","typeGuard":"static boolean hasTtl(Duration ttl) {\n    return ttl != null && !ttl.isNegative() && !ttl.isZero();\n}","tryCatchPattern":"try {\n    args = new SetArgs().ex(ttl);\n} catch (IllegalArgumentException e) {\n    log.warn(\"No valid TTL configured, setting key without expiration\");\n    args = new SetArgs();\n}","preventionTips":["Default nullable config Durations via @ConfigMapping defaults or Optional.orElse.","Never pass Optional.get() or possibly-null fields directly into SetArgs builders.","Centralize SetArgs construction in one helper that validates inputs."],"tags":["redis","null-check","argument-validation"],"backgroundTag":"null-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"}