From 7fa25aa5b1944caa2efd1bd7d241f61d7b847cde Mon Sep 17 00:00:00 2001 From: "vercel[bot]" <35613825+vercel[bot]@users.noreply.github.com> Date: Mon, 5 Oct 2026 16:04:18 +0000 Subject: [PATCH 1/2] [docs] Note that throttled step-result writes don't re-run the step body Co-Authored-By: Claude Signed-off-by: Pranay Prakash <1797812+pranaygp@users.noreply.github.com> Co-Authored-By: Pranay Prakash <1797812+pranaygp@users.noreply.github.com> --- .changeset/docs-throttled-step-results.md | 4 ++++ docs/content/docs/v5/foundations/errors-and-retries.mdx | 2 ++ docs/content/worlds/v5/building-a-world.mdx | 2 ++ 3 files changed, 8 insertions(+) create mode 100644 .changeset/docs-throttled-step-results.md diff --git a/.changeset/docs-throttled-step-results.md b/.changeset/docs-throttled-step-results.md new file mode 100644 index 0000000000..639e57db6f --- /dev/null +++ b/.changeset/docs-throttled-step-results.md @@ -0,0 +1,4 @@ +--- +--- + +Docs: note that throttled step-result writes on Vercel no longer re-run the step body, and document `afterStepBody` for World authors. diff --git a/docs/content/docs/v5/foundations/errors-and-retries.mdx b/docs/content/docs/v5/foundations/errors-and-retries.mdx index ee2ceddbc6..321e90da5b 100644 --- a/docs/content/docs/v5/foundations/errors-and-retries.mdx +++ b/docs/content/docs/v5/foundations/errors-and-retries.mdx @@ -172,6 +172,8 @@ The SDK also replaces its shared events connection pool after repeated HTTP/2 se A connection failure does not prove that the backend rejected a write: it may have accepted it before the response was lost. Continue to make step side effects [idempotent](/docs/foundations/idempotency). +When the Vercel backend rate-limits (429) the write that records a step's result, the SDK keeps retrying it until the invocation's deadline, where other throttled writes give up after 30 seconds. A throttled result write therefore doesn't re-run the step body, repeat its side effects, or use up one of its retries. + Failed-run logs include the underlying error causes and their codes, exposing socket, DNS, or TLS errors behind messages such as `TypeError: fetch failed`. If a cause cannot be read, the log includes `[unavailable cause]` and the run can still be recorded as failed. ## Error codes diff --git a/docs/content/worlds/v5/building-a-world.mdx b/docs/content/worlds/v5/building-a-world.mdx index 168b1f32f7..01542b0e2d 100644 --- a/docs/content/worlds/v5/building-a-world.mdx +++ b/docs/content/worlds/v5/building-a-world.mdx @@ -158,6 +158,8 @@ interface Storage { **Batch writes:** `events.createBatch()` is optional, and implementing it is what declares it. The runtime folds a suspension's `step_created` and `wait_created` writes into batches only when the method exists, and otherwise takes the single-event path unchanged. Implement it with real atomicity per attempt, so a lost race leaves nothing behind, or do not implement it at all. The events land in request order at consecutive positions, and a concurrent writer may push the whole batch above the caller's view of the log. No skipped-event report accompanies the result, so a position-tracking caller compares the committed positions against what it expected and reloads. Reject the whole batch, with a request-level error, for `run_created`, `run_started`, `run_cancelled`, `hook_created`, `hook_disposed`, `attr_set`, for more events targeting one entity than a single write can express, and for a batch over your own size caps. The one legal same-entity pair is `step_created` followed by `step_started`, which creates the step born-running, and there the input must ride the `step_created`. +**Throttled step results:** `step_completed`, `step_retrying`, and a `step_failed` marked with `afterStepBody: true` in `CreateEventParams` record a step body that already ran. If your World retries throttled writes, keep these waiting longer than other writes, because losing one to queue redelivery runs the body again. `@workflow/world-vercel` waits until the invocation's deadline. The flag is advisory, and a World may ignore it. + **Run creation:** For `run_created` events, the `runId` parameter may be a client-provided string or `null`. When `null`, your World generates and returns a new `runId`. **Event data resolution:** `events.list()` and `events.create()` accept `resolveData: 'skip-step-inputs'`, and the runtime replays with it. The World may leave `input` out of `step_created` and `step_started` events, and returns everything else as for `'all'`. Treat any value other than `'none'` as `'all'`, because a World that tests `resolveData === 'all'` strips step results and breaks every replay. Map the value with `entityResolveData()` from `@workflow/world` before passing it to an entity read. From ae7816964cb32ca2f15b8b803c9b049e02a34bf4 Mon Sep 17 00:00:00 2001 From: Peter Wielander Date: Mon, 5 Oct 2026 15:54:12 -0700 Subject: [PATCH 2/2] Update docs/content/docs/v5/foundations/errors-and-retries.mdx Signed-off-by: Peter Wielander --- docs/content/docs/v5/foundations/errors-and-retries.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/content/docs/v5/foundations/errors-and-retries.mdx b/docs/content/docs/v5/foundations/errors-and-retries.mdx index 321e90da5b..ee2ceddbc6 100644 --- a/docs/content/docs/v5/foundations/errors-and-retries.mdx +++ b/docs/content/docs/v5/foundations/errors-and-retries.mdx @@ -172,8 +172,6 @@ The SDK also replaces its shared events connection pool after repeated HTTP/2 se A connection failure does not prove that the backend rejected a write: it may have accepted it before the response was lost. Continue to make step side effects [idempotent](/docs/foundations/idempotency). -When the Vercel backend rate-limits (429) the write that records a step's result, the SDK keeps retrying it until the invocation's deadline, where other throttled writes give up after 30 seconds. A throttled result write therefore doesn't re-run the step body, repeat its side effects, or use up one of its retries. - Failed-run logs include the underlying error causes and their codes, exposing socket, DNS, or TLS errors behind messages such as `TypeError: fetch failed`. If a cause cannot be read, the log includes `[unavailable cause]` and the run can still be recorded as failed. ## Error codes