aws / aws/aws-durable-execution-sdk-java

[Bug]: waitForCondition exhaustion can produce FAILED invocation without ErrorObject

Offen
#634 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
bug java pkg:sdk
Vorherrschende Sprache
Java
Sterne
28
Forks
11
Ø Merge
1 T. 8 Std.
Gemergte PRs (30 T.)
47

Beschreibung

### Expected Behavior

When `waitForCondition` exhausts its configured attempts, the SDK should:

1. Checkpoint the `WaitForCondition` step as `FAILED` with a non-null `ErrorObject`.
2. Checkpoint an enclosing synchronous child context as `FAILED` with a non-null `ErrorObject`.
3. Return a root `DurableExecutionInvocationOutput` with `Status=FAILED` and a non-null `ErrorObject`.

This ensures replay preserves useful diagnostics and any service/emulator consuming the invocation result can reliably record the execution as failed.

### Actual Behavior

The built-in wait strategies throw `WaitForConditionFailedException(String)`, whose `DurableOperationException` state has a null `ErrorObject`.

That null propagates through the failure path:

- `WaitForConditionOperation.handleCheckFailure()` reuses `DurableOperationException.getErrorObject()` without a null fallback.
- `ChildContextOperation.handleChildContextFailure()` does the same.
- `DurableExecutor.buildErrorObject()` returns `DurableOperationException.getErrorObject()` directly, even when it is null.

The final invocation output can therefore be equivalent to:

```json
{
"Status": "FAILED"
}
```

The Java `LocalDurableTestRunner` preserves the `FAILED` status, but the error is absent. When used through SAM Local, this combines with an emulator bug that currently converts `FAILED` with no error into `ExecutionSucceeded`.

### Steps to Reproduce

Use a synchronous child context containing a condition that never stops polling:

```java
var runner = LocalDurableTestRunner.create(String.class, (input, ctx) ->
ctx.runInChildContext("child", String.class, child ->
child.waitForCondition(
"poll",
String.class,
(state, stepCtx) -> WaitForConditionResult.continuePolling(state),
WaitForConditionConfig.builder()
.waitStrategy(WaitStrategies.fixedDelay(
2, Duration.ofSeconds(1)))
.build())));

var result = runner.runUntilComplete("test");
```

The local runner reports `FAILED`, but the root error is absent. Running the equivalent handler through SAM Local can produce this history:

```text
StepFailed (WaitForCondition)
ContextFailed (RunInChildContext)
InvocationCompleted
ExecutionSucceeded
```

### SDK Version

`2.1.0`; the behavior is also present on current `2.1.1-SNAPSHOT` / `main` as of 2026-08-19.

### Java Version

17

### Is this a regression?

No known working version.

### Last Working Version

N/A

### Proposed Fix

Always fall back to serializing the thrown exception when an SDK exception has no embedded error:

```java
if (e instanceof DurableOperationException operationException
&& operationException.getErrorObject() != null) {
return operationException.getErrorObject();
}
return ExceptionHelper.buildErrorObject(e, serDes);
```

Apply equivalent null fallbacks when checkpointing failures in `WaitForConditionOperation` and `ChildContextOperation`, so operation history and replay also retain the error.

Add an integration test for max-attempt exhaustion inside synchronous `runInChildContext` that asserts:

- the step is failed with error details;
- the child context is failed with error details;
- the root invocation is `FAILED` with an error.

### Related Issue

The SAM Local emulator status-handling defect exposed by this null error is tracked in aws/aws-durable-execution-sdk-python#656.

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne mit WaitForConditionOperation.handleCheckFailure(), ChildContextOperation.handleChildContextFailure() und DurableExecutor.buildErrorObject(), und führe dann die synchrone Reproduktion von runInChildContext mit LocalDurableTestRunner aus. Füge die Fallbacks für null-Fehler und einen Integrationstest hinzu, der das Ausschöpfen der maximalen Versuchsanzahl abdeckt. Als abgeschlossen gilt die Aufgabe, wenn der Schritt, der Child-Kontext und der Root-Aufruf alle FAILED sind und Fehlerdetails enthalten.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
java
Bereich
backend, testing
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
68/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.