You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
mutation-cargo.yml's "Relocate workflow source" step (added to fix #343) moves workflow-src/ out of the caller's workspace immediately
after the "Setup Rust" step runs. "Setup Rust" is a local composite
action invoked as uses: ./workflow-src/.github/actions/setup-rust,
and it wraps actions-rust-lang/setup-rust-toolchain, which registers
an automatic post step (Post Setup Rust) to save the cargo cache
when the restore was only a partial (restore-key) match. That post
step runs at the very end of the job — after "Relocate workflow
source" has already moved (not copied) the directory — so the runner
can no longer resolve the composite action's action.yml at its
original path and the whole job fails, even though the actual mutation
run succeeded.
2026-07-19T06:43:41Z Cache hit for restore-key: Linux-cargo--e4fedeec3d03d6da393d669f34e5377b094a4000d18ff87a2535c2224510ce46
...
2026-07-19T06:43:59Z ##[error]Can't find 'action.yml', 'action.yaml' or 'Dockerfile' under '/home/runner/work/wildside-engine/wildside-engine/workflow-src/.github/actions/setup-rust'. Did you forget to run actions/checkout before running your local action?
The "Run mutation testing" and "Upload mutation report" steps both
succeeded and the mutation report was uploaded, but "Post Setup Rust"
failed, so the job (and the whole run) is reported as a failure.
The fault is conditional on the cache restore being a partial match
(restore-key) rather than an exact key hit: an exact hit skips the
save and the post step never touches action.yml, so the run passes.
This explains why adjacent scheduled runs at the same pinned SHA
(e0d9b652b137eb15314fff188f09e1ba18d3cc5b) on 2026-07-18 and
2026-07-20 were green while the 2026-07-19 run failed — the workspace
had drifted enough to miss the exact cache key that day.
Root cause
mutation-cargo.yml (job mutation, steps around lines 195-273):
The comment on "Relocate workflow source" already acknowledges it must
run after "Setup Rust" needs the workspace-local action path, but it
overlooks that GitHub Actions runs any registered post steps for
composite/JS actions at job teardown, in reverse order, regardless of
where the main steps sit in the job. Moving (rather than copying, or
leaving a resolvable stand-in behind) workflow-src before teardown
breaks any earlier step whose action registers a post hook needing its
own action.yml.
Impact
Estate-wide, intermittent: any caller of mutation-cargo.yml whose
cargo cache restore is a partial match on a given scheduled run gets a
spurious job failure, even though the mutation testing itself
completed and uploaded correctly. This is confusing for the 14-day
mutation-testing sweep — failures look like real setup breakage but
are a shared-actions teardown bug.
Suggested fix
Pick one:
Copy workflow-src to $RUNNER_TEMP instead of moving it, and leave
a symlink at the original path pointing to the copy. git ls-files-based hygiene checks (the caller-side mitigation already
recommended in workflow-src checkout pollutes the caller's tree during mutation runs #343) won't see it, and os.walk-style checks that
don't follow symlinks (the default) also won't descend into it, but
the runner can still resolve action.yml for any post hooks
registered against the original path.
Or check out workflow-src directly under $RUNNER_TEMP from the
start (path: ${{ runner.temp }}/workflow-src on the initial
checkout) rather than checking it out inside the workspace and
relocating afterwards, if a local uses: path outside the workspace
is viable for "Setup Rust".
Either way, workflow-src (or something that resolves to its action.yml files) needs to remain reachable at its original path for
the lifetime of the job, not just until the last explicit step that
references it.
Summary
mutation-cargo.yml's "Relocate workflow source" step (added to fix#343) moves
workflow-src/out of the caller's workspace immediatelyafter the "Setup Rust" step runs. "Setup Rust" is a local composite
action invoked as
uses: ./workflow-src/.github/actions/setup-rust,and it wraps
actions-rust-lang/setup-rust-toolchain, which registersan automatic post step (
Post Setup Rust) to save the cargo cachewhen the restore was only a partial (
restore-key) match. That poststep runs at the very end of the job — after "Relocate workflow
source" has already moved (not copied) the directory — so the runner
can no longer resolve the composite action's
action.ymlat itsoriginal path and the whole job fails, even though the actual mutation
run succeeded.
Observed
leynos/wildside-engine, run
https://github.com/leynos/wildside-engine/actions/runs/29676888803
(scheduled, 2026-07-19), job "mutation / mutants (...)":
The "Run mutation testing" and "Upload mutation report" steps both
succeeded and the mutation report was uploaded, but "Post Setup Rust"
failed, so the job (and the whole run) is reported as a failure.
The fault is conditional on the cache restore being a partial match
(
restore-key) rather than an exact key hit: an exact hit skips thesave and the post step never touches
action.yml, so the run passes.This explains why adjacent scheduled runs at the same pinned SHA
(
e0d9b652b137eb15314fff188f09e1ba18d3cc5b) on 2026-07-18 and2026-07-20 were green while the 2026-07-19 run failed — the workspace
had drifted enough to miss the exact cache key that day.
Root cause
mutation-cargo.yml(jobmutation, steps around lines 195-273):The comment on "Relocate workflow source" already acknowledges it must
run after "Setup Rust" needs the workspace-local action path, but it
overlooks that GitHub Actions runs any registered post steps for
composite/JS actions at job teardown, in reverse order, regardless of
where the main steps sit in the job. Moving (rather than copying, or
leaving a resolvable stand-in behind)
workflow-srcbefore teardownbreaks any earlier step whose action registers a post hook needing its
own
action.yml.Impact
Estate-wide, intermittent: any caller of
mutation-cargo.ymlwhosecargo cache restore is a partial match on a given scheduled run gets a
spurious job failure, even though the mutation testing itself
completed and uploaded correctly. This is confusing for the 14-day
mutation-testing sweep — failures look like real setup breakage but
are a shared-actions teardown bug.
Suggested fix
Pick one:
workflow-srcto$RUNNER_TEMPinstead of moving it, and leavea symlink at the original path pointing to the copy.
git ls-files-based hygiene checks (the caller-side mitigation alreadyrecommended in workflow-src checkout pollutes the caller's tree during mutation runs #343) won't see it, and
os.walk-style checks thatdon't follow symlinks (the default) also won't descend into it, but
the runner can still resolve
action.ymlfor any post hooksregistered against the original path.
workflow-srcdirectly under$RUNNER_TEMPfrom thestart (
path: ${{ runner.temp }}/workflow-srcon the initialcheckout) rather than checking it out inside the workspace and
relocating afterwards, if a local
uses:path outside the workspaceis viable for "Setup Rust".
Either way,
workflow-src(or something that resolves to itsaction.ymlfiles) needs to remain reachable at its original path forthe lifetime of the job, not just until the last explicit step that
references it.