vercel / vercel/workflow

core: normal fresh inline wake races emit misleading in-flight step warnings

Open
#4,265 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
2.4k
Forks
365
Avg merge
2d 11h
Merged PRs (30d)
169

Description

Problem

Normal concurrent wakeups can print the following warning to stderr even when the step executes once and completes immediately:

[workflow-sdk] Step execution already in flight in this process; awaiting its settlement instead of executing again

In an eve terminal session this appears as a prominent stderr warning during successful background delegation, making the run look broken. This report is about incorrect log severity; the captured run did not deadlock or lose its result.

Observed environment and reproduction

  • eve 0.62.0, bundling @workflow/core@5.0.0-beta.53
  • Local Node.js dev server and filesystem Workflow world, started with bun deveve dev
  • Root agent delegated a repository architecture investigation through its built-in background agent tool.
  • Hook wakeups overlapped while the task workflow was executing fresh inline notification steps.

The behavior is timing-dependent. In the captured run (wrun_01M2X3QZMBEXQ94J53DZA33R0Q), the warning was emitted at exactly the recorded start of wakeTaskAgentRequestParentStep, not after an ownership lease expired.

Durable evidence

Times below are UTC on 2026-09-19, from the local Workflow event log and eve session stream:

Event Time
Warning and reported step start 15:14:49.799
Reported step completes, attempt 1 15:14:49.812
Child finishes and notifies its caller 15:16:26.943
Task workflow completes 15:16:27.043
Parent resumes automatically 15:16:27.076
Parent finishes its architecture report 15:17:00.057

The reported step has exactly one step_started and one step_completed event. Three later warnings on the same task also accompany successful notification steps completing within 9–17 ms. There were no failed or cancelled research turns.

The terminal's earlier Done in 11s only ended the initial parent turn; the child continued in the background and its completion triggered the later parent response.

Root cause and expected behavior

In the bundled runtime, all fresh inline steps use runStepSingleFlight. A concurrent wake replay can reach the same new step while another invocation is already executing it. The guard correctly waits for the first invocation and avoids executing the body again, but it logs every collision at warning level.

Fresh inline contention should be a debug diagnostic, preserving the run/step IDs, deduplication, and wait-for-settlement behavior. Recovery/backstop contention can retain its warning.

Fix: #4266. Current main already bypasses single-flight for fresh Node claims after #3568; #4266 preserves that dispatch policy and quiets the remaining expected QuickJS contention. Recovery and background-step warnings remain unchanged.

Review of the earlier draft

Checked out PR #4254 at dda43f480d6d8293f2abf433f6645d0dd20d9e5b in an isolated worktree. All seven committed step-single-flight tests passed. Four additional temporary real-console assertions passed when comparing against pre-PR commit 86a88beed86aa226002cc3c39ab6b8edad2beb7a:

  • The original helper warns for fresh contention.
  • The fixed helper is silent by default for fresh contention.
  • DEBUG=workflow:runtime:debug retains the diagnostic and run/step IDs.
  • Recovery contention continues to warn.

Every comparison also verifies one body execution and that the competing invocation remains pending until the first invocation settles, then skips.

eve's existing TUI test renders background completion after two quiet minutes without another user message passed as well. No eve execution or terminal lifecycle change was needed for this report. The helper-only checks did not cover the draft's integration with pre-claimed ownership. Further investigation reproduced the P1 review finding on #4254: a failed pre-claim entering single-flight first suppresses the actual owner, and a step with maxRetries: 0 fails on recovery without executing its body. #4266 avoids this regression by preserving Node dispatch on current main.

Validation of #4266

The independent fix has 2,590 passing core tests (plus three expected-failure cases and one skipped test), passing build and typecheck, and a new regression exercising two overlapping QuickJS entrypoint invocations through the real single-flight guard and logger. Removing the debug argument makes that regression fail. It verifies one execution, no default warning, and that both invocations wait for the owner to settle. Changeset and focused Biome checks also passed (Biome reports existing warnings in the entrypoint).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the runStepSingleFlight entry point and the existing step-single-flight tests. Run the focused tests and inspect the QuickJS entrypoint regression described in the report, then verify that fresh contention executes once, waits for settlement, emits no default warning, and preserves recovery warnings.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.