Fix NPE in TryExecutor when retry policy omits optional fields#1519
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses runtime NullPointerException failures when a RetryPolicy omits optional fields (as allowed by the spec) by adding defaulting/guard logic in the retry executor path and adding regression tests for common omission scenarios.
Changes:
- Default retry backoff to constant backoff when
retryPolicy.backoffis omitted. - Default retry limit to a max when
retryPolicy.limit/limit.attemptis omitted. - Default retry delay to
Duration.ZEROwhenretryPolicy.delayis omitted. - Add fluent DSL tests covering retry behavior when
backoff,limit, ordelayare omitted.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| impl/core/src/main/java/io/serverlessworkflow/impl/executors/TryExecutor.java | Adds resolveMaxAttempts() and defaults missing backoff to constant backoff. |
| impl/core/src/main/java/io/serverlessworkflow/impl/executors/retry/AbstractRetryIntervalFunction.java | Defaults missing delay to zero duration via a constant resolver. |
| experimental/test/src/test/java/io/serverlessworkflow/fluent/test/FuncTryCatchTest.java | Adds regression tests for retry policies missing backoff, limit, or delay. |
Comments suppressed due to low confidence (1)
impl/core/src/main/java/io/serverlessworkflow/impl/executors/retry/AbstractRetryIntervalFunction.java:42
- The constructor still dereferences
jitter.getFrom()/jitter.getTo()without guarding against them being null. The fluent builder allows setting only one of these, so this path can still throw a NullPointerException even with the top-leveljitter != nullcheck. Suggest treating missingfrom/toas no jitter (Duration.ZERO).
if (jitter != null) {
minJitteringResolver = Optional.of(WorkflowUtils.fromTimeoutAfter(appl, jitter.getFrom()));
maxJitteringResolver = Optional.of(WorkflowUtils.fromTimeoutAfter(appl, jitter.getTo()));
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
fjtirado
reviewed
Jul 6, 2026
fjtirado
reviewed
Jul 6, 2026
fjtirado
approved these changes
Jul 6, 2026
fjtirado
left a comment
Collaborator
There was a problem hiding this comment.
Just usual picky comments ;)
fjtirado
force-pushed
the
issue-1517
branch
3 times, most recently
from
July 9, 2026 17:23
b599648 to
f843a29
Compare
fjtirado
reviewed
Jul 9, 2026
Signed-off-by: fjtirado <ftirados@ibm.com>
Comment on lines
+117
to
+121
| private static int resolveMaxAttempts(RetryLimit limit) { | ||
| return limit != null && limit.getAttempt() != null | ||
| ? limit.getAttempt().getCount() | ||
| : Integer.MAX_VALUE - 1; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The spec defines backoff, limit, and delay as optional in a retry policy, but the runtime assumed all three were always present, causing NullPointerException when any was omitted.
Closes #1517