{"record":{"id":"3e18d83990b0c58d","repo":"flowable/flowable-engine","slug":"max-wait-timeout-has-to-be-positive-it-was","errorCode":null,"errorMessage":"max wait timeout has to be positive. It was ","messagePattern":"max wait timeout has to be positive\\. It was ","errorType":"validation","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/agenda/WaitForAnyFutureToFinishOperation.java","lineNumber":40,"sourceCode":"\nimport org.flowable.common.engine.api.FlowableException;\n\n/**\n * @author Filip Hrisafov\n */\npublic class WaitForAnyFutureToFinishOperation implements Runnable {\n\n    protected final Agenda agenda;\n    protected final List<ExecuteFutureActionOperation<?>> futureOperations;\n    protected final Duration timeout;\n\n    public WaitForAnyFutureToFinishOperation(Agenda agenda, List<ExecuteFutureActionOperation<?>> futureOperations, Duration timeout) {\n        this.agenda = agenda;\n        this.futureOperations = futureOperations;\n        if (timeout == null) {\n            this.timeout = null;\n        } else if (timeout.isNegative() || timeout.isZero()) {\n            throw new FlowableException(\"max wait timeout has to be positive. It was \" + timeout);\n        } else {\n            this.timeout = timeout;\n        }\n    }\n\n    @Override\n    public void run() {\n        CompletableFuture[] anyOfFutures = new CompletableFuture[futureOperations.size()];\n\n        for (int i = 0; i < futureOperations.size(); i++) {\n            anyOfFutures[i] = futureOperations.get(i).getFuture();\n        }\n        try {\n            CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(anyOfFutures);\n            if (timeout == null) {\n                // This blocks until at least one is future is done\n                anyOfFuture.get();\n            } else {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/agenda/WaitForAnyFutureToFinishOperation.java#L22-L58","documentation":"Thrown in the WaitForAnyFutureToFinishOperation constructor when a non-null timeout Duration is zero or negative. The agenda requires a strictly positive max wait duration when one is provided; a null timeout is allowed and means wait indefinitely.","triggerScenarios":"Planning a WaitForAnyFutureToFinishOperation with Duration.ZERO, a negative duration (e.g. from a misconfigured property), or a computed duration that underflowed to zero.","commonSituations":"Configuration value parsed as '0' or 'PT0S'; a computed remaining-time duration that hit zero before the wait was scheduled; unit confusion (e.g. millis passed where seconds expected yielding 0).","solutions":["Pass Duration.ofMillis(...)/ofSeconds(...) with a strictly positive amount, or pass null to wait without a timeout.","Validate configuration before constructing: if timeout != null && timeout.isZero() || timeout.isNegative() fix the config value.","Fix code computing remaining time so zero/negative remaining durations are treated as null (no timeout) or a minimum positive floor.","Check for unit mistakes when converting config strings (PT0S vs PT1S)."],"exampleFix":"// before\nDuration timeout = Duration.between(now, deadline); // may be <= 0\nnew WaitForAnyFutureToFinishOperation(agenda, ops, timeout);\n// after\nDuration timeout = deadline.isAfter(now) ? Duration.between(now, deadline) : null;\nnew WaitForAnyFutureToFinishOperation(agenda, ops, timeout);","handlingStrategy":"validation","validationCode":"if (timeout != null && (timeout.isZero() || timeout.isNegative())) {\n  throw new IllegalArgumentException(\"max wait timeout must be positive, got \" + timeout);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp computed durations to a positive minimum or map non-positive values to null (no timeout).","Validate timeout configuration properties at startup.","Watch for unit conversion producing zero durations (millis truncation)."],"tags":["agenda","timeout","argument-validation","duration"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}