Repository navigation
Description
What would you like?
When a checkpoint response arrives without a CheckpointToken, the SDK should treat it as a signal that the service will accept no further checkpoints from this invocation. The SDK should stop issuing checkpoints and end the invocation cleanly with Status: PENDING.
Why PENDING and not FAILED or a thrown error:
- A missing token does not mean the execution is finished. It means this invocation cannot make further progress. The invocation result must not claim the execution finished.
- A thrown error is an invocation failure. Lambda retries it, but the retry has no valid token and can do nothing useful. It also puts an error in customer logs for a condition the SDK understood.
- PENDING is already what the SDK returns for every suspend (wait, scheduled retry, pending callback). This is a suspend: the invocation is done for now and the execution continues later.
Current behavior
(alpha branch at 7183f03; main is README-only.)
durable/checkpoint.go treats a missing token as a plain error:
if out.CheckpointToken == nil {
return errors.New("durable: checkpoint: backend returned no checkpoint token")
}The step returns that error to the handler. durable/handler.go turns any handler error into Status: FAILED. So a missing token is an execution failure today.
The SDK already has the right shape for the fix. checkpointer.terminate() makes later checkpoint calls return errCheckpointTerminated, and every operation translates that into errSuspendExecution, which the handler maps to Status: PENDING.
Possible Implementation
- In
checkpointer.checkpoint, whenout.CheckpointToken == nil, callcp.terminate()and returnerrCheckpointTerminatedinstead of a plain error. The existing translation toerrSuspendExecutionthen yieldsPENDINGwith no change to the operations or the handler. - The current
errCheckpointTerminatedpath already abandons in-flight branches without further checkpoints; that is the correct behavior here. Abandoned operations replay on the next invocation. AT_MOST_ONCE steps whose START landed in the last accepted checkpoint will not run again, which is the defined semantics of AT_MOST_ONCE. - Unit test: a checkpoint response with a nil token produces
Status: PENDING, no further checkpoint calls, and no error in the response. - Testing support: the local runner needs a way to omit the token on a chosen checkpoint so customers can test their handlers against this path.
Is this a breaking change?
No. The SDK's response set is unchanged; a new internal suspension cause is added.
Additional Context
- Prerequisite: [Bug]: Stale checkpoint token fails the execution; no stale-token carve-out in classifyCheckpointError #6 (stale-token classification). That fix is the fallback path whenever the missing token is not detected, so it should land first.
- Sibling issues in the other SDKs are linked in a comment below.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
yaythomas commentedon Sep 12, 2026
Sibling issues (same feature, one per SDK):
yaythomas commentedon Sep 20, 2026
Resolved by d678883 (
fix(durable): halt on stale or no checkpoint token), now onmain. That commit implements what this issue asks for without naming it.