sangkyoonnam opened a new issue, #1170: URL: https://github.com/apache/flink-agents/issues/1170
### Search before asking - [x] I searched in the [issues](https://github.com/apache/flink-agents/issues) and found nothing similar. ### Description A durable call whose callable returns `null` is recorded as a success with no result payload, and replaying it throws `NullPointerException`: `RunnerContextImpl#tryGetCachedResult` returns `Optional.of(null)` for that slot. When recovery replays an unfinished action and reaches this recorded call, it throws again on every attempt; if the exception escapes the action, the action can't be recovered from that saved state. The built-in async sub-agent path hits it. `BaseAsyncSubagentSetup#submitRequest` is a `DurableCallable<Void>` with a reconciler, run through `durableExecuteAsync`, and `ToolCallAction` submits the sub-agent and awaits its result in the same action. If the job fails over while the action waits, the replayed submit throws; `ToolCallAction` catches it and reports the sub-agent as failed, so the wait for the remote run, which was already started, never resumes. `serializeDurableResult(null)` returns `null`, so the slot is stored as SUCCEEDED with neither payload. Both callers of `tryGetCachedResult` hit it: `durableExecuteCompletionOnly` (`durableExecute` or `durableExecuteAsync` without a reconciler) and the terminal-slot branch of `durableExecuteWithReconcile`. `readTerminalOutcomeAt`, used by the Java batch `gather`, already returns `Outcome.success(null)` for the same slot. The Python runtime is unaffected; its cache lookup keeps the hit flag separate from the value. Expected: replay returns `null` without running the callable or the reconciler again, and the recorded call is not duplicated. #1155 (open) changes the signature of `tryGetCachedResult` but keeps this branch, so a fix and #1155 touch the same method. I'm happy to rebase onto it if it lands first. ### How to reproduce ```java // Inside an action: a Void side effect. ctx.durableExecute(voidCallable); // returns null; slot recorded as SUCCEEDED with no payload // The job fails over and the action replays from the saved action state: ctx.durableExecute(voidCallable); // java.lang.NullPointerException // at java.base/java.util.Objects.requireNonNull(Objects.java:233) // at java.base/java.util.Optional.of(Optional.java:113) // at org.apache.flink.agents.runtime.context.RunnerContextImpl.tryGetCachedResult(RunnerContextImpl.java:933) // at org.apache.flink.agents.runtime.context.RunnerContextImpl.durableExecuteCompletionOnly(RunnerContextImpl.java:624) // ... ``` With a reconciler, as in the sub-agent path, the same slot fails through `durableExecuteWithReconcile` (line 982). ### Version and environment main (`2e97add7`). JDK 21, OS independent. Java runtime only. ### Are you willing to submit a PR? - [x] I'm willing to submit a PR! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
