Skip to content

fix(run): propagate the Actor's non-zero exit code#1195

Open
l2ysho wants to merge 2 commits into
masterfrom
1190-ultra-review-apify-run-exits-0-when-the-actor-fails
Open

fix(run): propagate the Actor's non-zero exit code#1195
l2ysho wants to merge 2 commits into
masterfrom
1190-ultra-review-apify-run-exits-0-when-the-actor-fails

Conversation

@l2ysho
Copy link
Copy Markdown
Contributor

@l2ysho l2ysho commented Jun 8, 2026

What & why

apify run exited with code 0 even when the Actor failed. The catch block wrapping execWithLog in RunCommand read stderr but never set process.exitCode or re-threw (it held only a TODO), so the error was swallowed and the command framework's process.exitCode ||= 1 never fired.

This silently broke CI and shell chains like apify run && deploy — a failing Actor looked successful to any caller inspecting the exit code.

Fixes #1190
Fixes #1180

Change

In the catch block, forward the child's exit code:

} catch (err) {
    process.exitCode = (err as ExecaError).exitCode ?? 1;
}
  • Preserves the Actor's exact exit code (e.g. process.exit(10) → CLI exits 10).
  • Falls back to 1 for signal-killed children, where ExecaError.exitCode is undefined.
  • No change to error output — execWithLog already prints the message and the Actor's own stdout/stderr is inherited regardless. Only the exit code was being lost.

Tests

Added a scenario test (test/local/__fixtures__/commands/run/javascript/propagates-non-zero-exit-code.test.ts) following the existing fixture convention: it scaffolds a project_empty Actor, copies in a failing main.js fixture that exits 10, runs it, and asserts the CLI's process.exitCode is 10.

Verified TDD red → green, plus end-to-end with the built CLI:

Actor stderr shown Error line shown Exit code
Before 0
After 10

lint, format, build, and test:local all pass; existing run tests unaffected.

Follow-up

Exit-code handling for execWithLog children is inconsistent across commands (run.ts, create.ts, upgrade.ts each differ), and exec.ts discards the friendly error it builds. Tracked in #1196 — out of scope for this fix.

l2ysho and others added 2 commits June 8, 2026 11:58
The catch block wrapping execWithLog read stderr but never set
process.exitCode or re-threw, so a failing Actor made the CLI exit 0.
The command framework's `exitCode ||= 1` never fired because the error
was swallowed here. This silently broke CI/shell chains like
`apify run && deploy`.

Forward the child's exit code (falling back to 1 for signal-killed
children) so the CLI exits non-zero when the Actor fails.

Closes #1180, #1190

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@l2ysho l2ysho self-assigned this Jun 8, 2026
@l2ysho l2ysho added the t-dx Issues owned by the DX team. label Jun 8, 2026
@github-actions github-actions Bot added this to the 142nd sprint - Tooling team milestone Jun 8, 2026
@github-actions github-actions Bot added the tested Temporary label used only programatically for some analytics. label Jun 8, 2026
@l2ysho l2ysho changed the title 1190 ultra review apify run exits 0 when the actor fails fix(run): propagate the Actor's non-zero exit code Jun 8, 2026
@l2ysho l2ysho marked this pull request as ready for review June 8, 2026 12:55
@l2ysho l2ysho requested a review from vladfrangu as a code owner June 8, 2026 12:55
@l2ysho
Copy link
Copy Markdown
Contributor Author

l2ysho commented Jun 8, 2026

@vladfrangu this issue popped up in 2 different ways so I took a look. Just do not no why it was done this way in a first place (like always swallow error), maybe there was some reason I am not aware of? also feel free to check this follow up

Comment thread src/commands/run.ts
Comment on lines -450 to -454
const { stderr } = err as ExecaError;

if (stderr) {
// TODO: maybe throw in helpful tips for debugging issues (missing scripts, trying to start a ts file with old node, etc)
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't remove the old code with the cast but ik we had some ideas to inspect the stderr output and give hints. Idk why we never propagated the exitCode tho 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-dx Issues owned by the DX team. tested Temporary label used only programatically for some analytics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ultra-review] apify run exits 0 when the Actor fails The run command swallows the non-zero exit code

4 participants