Skip to content

Local-dev step stack traces: wrong lines, and function names that depend on step-executor.ts line offsets #4352

Open

Description

@pranaygp

The E2E Local Dev Tests step-error assertions (packages/core/e2e/e2e.test.ts, "basic step error preserves message and stack trace" and "cross-file step error preserves message and function names in stack") pass or fail depending on unrelated line offsets in packages/core/src/runtime/step-executor.ts. On current main they pass by coincidence.

Reproduction (sveltekit, pnpm dev, same env as the CI job)

  • main @ 2694663ae: pass. The reported frame is at errorStepFn (workbench/example/workflows/99_e2e.ts:992:11), so the name is right, but the line isn't: errorStepFn throws at line 1424.
  • main + five comment-only lines inserted in step-executor.ts above the step call (// inert ×5 before const createEvent in executeStep): both tests fail. The frame becomes at _a (…/99_e2e.ts:992:11), and the cross-file test reports at _a (…/helpers.ts:21:22). dev.test.ts isn't needed to trigger it, and it happens with both WORKFLOW_VM=node and quickjs.
  • CI hit the same thing on all four astro/sveltekit × node/quickjs local-dev jobs of [core] Don't download recorded step inputs on replay (resolveData: 'skip-step-inputs') #4348, whose first revision added five lines to that function. On CI's retry, the name moved to a different wrong function (hookGetConflictWithPriorStepWorkflow).

What's going on

  1. Positions: packages/builders/src/apply-swc-transform.ts runs the SWC transform with sourceMaps: false, with a TODO to investigate. Step-bundle positions therefore point into the transformed code instead of the original file. That's why every step frame reads 99_e2e.ts:992 whatever the throw site is.
    • As an experiment, sourceMaps: 'inline' makes the position correct (99_e2e.ts:1424:9).
    • It also doubles the path (workbench/example/workflows/example/workflows/99_e2e.ts), so the source paths in the map need fixing too.
  2. Names: with (1) fixed, the name is still _a. The frame name comes from source-map name resolution rather than from V8's function name. For Node's --enable-source-maps, that's the enclosing-function or caller-site entry in the map, plus Vite's SSR module runner for eval'd modules. So an offset in how those positions are looked up makes the name depend on where code lands in step-executor.ts.

Impact

Any PR that shifts lines in step-executor.ts can fail these four required jobs for reasons unrelated to its change. Separately, dev-mode step stacks report wrong lines today.

Suggested fix

Emit and chain the SWC transform's source map into the esbuild step bundle, fixing the sources paths. Then check how function names are resolved for step frames in the dev SSR runner, or have the test assert on the frame position instead of relying on the source-map name.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions