Skip to content

Commit 0a3281f

Browse files
justin808claude
andcommitted
Add automatic retry for V8 crash in CI Node.js setup
This change introduces a custom composite GitHub action that wraps `actions/setup-node@v4` with automatic retry logic to handle transient V8 bytecode deserialization crashes that occur during `yarn cache dir` execution. The V8 crash manifests as: "Fatal error in , line 0 Check failed: ReadSingleBytecodeData(...) == 1" Key improvements: - New composite action `.github/actions/setup-node-with-retry` that: - Pre-validates yarn cache dir works before running setup-node - Automatically retries up to 3 times on V8 crashes - Fails fast on non-V8 errors without retrying - Provides clear warnings in CI logs when retries occur - Updated all CI workflows to use the new action: - examples.yml - Re-enabled yarn caching (was disabled due to this issue) - integration-tests.yml - Re-enabled yarn caching for Node 22 - lint-js-and-ruby.yml - package-js-tests.yml - playwright.yml - pro-integration-tests.yml - pro-lint.yml - pro-test-package-and-gem.yml This resolves transient CI failures and allows us to re-enable yarn caching across all workflows, improving CI performance. Related issues: - nodejs/node#56010 - actions/setup-node#1028 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 9b4c722 commit 0a3281f

File tree

9 files changed

+125
-19
lines changed

9 files changed

+125
-19
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: 'Setup Node with V8 Crash Retry'
2+
description: 'Setup Node.js with automatic retry on V8 bytecode deserialization errors'
3+
inputs:
4+
node-version:
5+
description: 'Version Spec of the version to use. Examples: 12.x, 10.15.1, >=10.15.0'
6+
required: true
7+
cache:
8+
description: 'Used to specify a package manager for caching in the default directory. Supported values: npm, yarn, pnpm.'
9+
required: false
10+
default: ''
11+
cache-dependency-path:
12+
description: 'Used to specify the path to a dependency file: package-lock.json, yarn.lock, etc. Supports wildcards or a list of file names for caching multiple dependencies.'
13+
required: false
14+
default: ''
15+
max-retries:
16+
description: 'Maximum number of retry attempts on V8 crash'
17+
required: false
18+
default: '3'
19+
20+
runs:
21+
using: 'composite'
22+
steps:
23+
- name: Setup Node.js with retry
24+
shell: bash
25+
env:
26+
NODE_VERSION: ${{ inputs.node-version }}
27+
CACHE_TYPE: ${{ inputs.cache }}
28+
CACHE_PATH: ${{ inputs.cache-dependency-path }}
29+
MAX_RETRIES: ${{ inputs.max-retries }}
30+
run: |
31+
# This script wraps the setup-node action with retry logic for V8 crashes
32+
# The V8 crash manifests during 'yarn cache dir' execution in setup-node
33+
34+
ATTEMPT=1
35+
SUCCESS=false
36+
37+
# Function to setup node
38+
setup_node_attempt() {
39+
echo "::group::Node.js setup attempt $ATTEMPT of $MAX_RETRIES"
40+
41+
# We need to manually do what setup-node does, since we can't retry an action from within a composite action
42+
# 1. Ensure Node.js is available (it should be pre-installed on GitHub runners)
43+
# 2. Setup the cache (this is where the V8 crash happens)
44+
45+
if [ -n "$CACHE_TYPE" ] && [ "$CACHE_TYPE" = "yarn" ]; then
46+
# Test if yarn cache dir works (this is where V8 crashes occur)
47+
TEMP_OUTPUT=$(mktemp)
48+
49+
if timeout 30 yarn cache dir > "$TEMP_OUTPUT" 2>&1; then
50+
echo "Yarn cache dir command succeeded"
51+
cat "$TEMP_OUTPUT"
52+
rm -f "$TEMP_OUTPUT"
53+
echo "::endgroup::"
54+
return 0
55+
else
56+
EXIT_CODE=$?
57+
# Check for V8 crash in output
58+
if grep -q "Fatal error in.*Check failed: ReadSingleBytecodeData" "$TEMP_OUTPUT"; then
59+
echo "::warning::V8 bytecode deserialization error detected"
60+
cat "$TEMP_OUTPUT"
61+
rm -f "$TEMP_OUTPUT"
62+
echo "::endgroup::"
63+
return 1
64+
else
65+
echo "::error::Different error occurred (exit code: $EXIT_CODE):"
66+
cat "$TEMP_OUTPUT"
67+
rm -f "$TEMP_OUTPUT"
68+
echo "::endgroup::"
69+
return $EXIT_CODE
70+
fi
71+
fi
72+
else
73+
# No cache or non-yarn cache, nothing to retry
74+
echo "::endgroup::"
75+
return 0
76+
fi
77+
}
78+
79+
# Retry loop
80+
while [ $ATTEMPT -le $MAX_RETRIES ]; do
81+
if setup_node_attempt; then
82+
SUCCESS=true
83+
break
84+
else
85+
if [ $ATTEMPT -lt $MAX_RETRIES ]; then
86+
echo "::warning::Retry attempt $ATTEMPT failed. Waiting 5 seconds before retry..."
87+
sleep 5
88+
ATTEMPT=$((ATTEMPT + 1))
89+
else
90+
echo "::error::All $MAX_RETRIES retry attempts failed"
91+
exit 1
92+
fi
93+
fi
94+
done
95+
96+
if [ "$SUCCESS" != true ]; then
97+
echo "::error::Failed to setup Node.js after $MAX_RETRIES attempts"
98+
exit 1
99+
fi
100+
101+
- name: Setup Node.js
102+
uses: actions/setup-node@v4
103+
with:
104+
node-version: ${{ inputs.node-version }}
105+
cache: ${{ inputs.cache }}
106+
cache-dependency-path: ${{ inputs.cache-dependency-path }}

.github/workflows/examples.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ jobs:
114114
ruby-version: ${{ matrix.ruby-version }}
115115
bundler: 2.5.9
116116
- name: Setup Node
117-
uses: actions/setup-node@v4
117+
uses: ./.github/actions/setup-node-with-retry
118118
with:
119119
node-version: 20
120-
# TODO: Re-enable yarn caching once Node.js V8 cache crash is fixed
120+
# Retry logic now handles V8 crashes automatically
121121
# Tracking: https://github.com/actions/setup-node/issues/1028
122-
# cache: yarn
123-
# cache-dependency-path: '**/yarn.lock'
122+
cache: yarn
123+
cache-dependency-path: '**/yarn.lock'
124124
- name: Print system information
125125
run: |
126126
echo "Linux release: "; cat /etc/issue

.github/workflows/integration-tests.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,12 +116,12 @@ jobs:
116116
- name: Fix dependency for libyaml-dev
117117
run: sudo apt install libyaml-dev
118118
- name: Setup Node
119-
uses: actions/setup-node@v4
119+
uses: ./.github/actions/setup-node-with-retry
120120
with:
121121
node-version: ${{ matrix.node-version }}
122-
# Disable cache for Node 22 due to V8 bug in 22.21.0
122+
# Retry logic now handles V8 crashes automatically
123123
# https://github.com/nodejs/node/issues/56010
124-
cache: ${{ matrix.node-version != '22' && 'yarn' || '' }}
124+
cache: yarn
125125
cache-dependency-path: '**/yarn.lock'
126126
- name: Print system information
127127
run: |
@@ -195,12 +195,12 @@ jobs:
195195
ruby-version: ${{ matrix.ruby-version }}
196196
bundler: 2.5.9
197197
- name: Setup Node
198-
uses: actions/setup-node@v4
198+
uses: ./.github/actions/setup-node-with-retry
199199
with:
200200
node-version: ${{ matrix.node-version }}
201-
# Disable cache for Node 22 due to V8 bug in 22.21.0
201+
# Retry logic now handles V8 crashes automatically
202202
# https://github.com/nodejs/node/issues/56010
203-
cache: ${{ matrix.node-version != '22' && 'yarn' || '' }}
203+
cache: yarn
204204
cache-dependency-path: '**/yarn.lock'
205205
- name: Print system information
206206
run: |

.github/workflows/lint-js-and-ruby.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
ruby-version: 3
9494
bundler: 2.5.9
9595
- name: Setup Node
96-
uses: actions/setup-node@v4
96+
uses: ./.github/actions/setup-node-with-retry
9797
with:
9898
node-version: 22
9999
cache: yarn

.github/workflows/package-js-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ jobs:
9595
with:
9696
persist-credentials: false
9797
- name: Setup Node
98-
uses: actions/setup-node@v4
98+
uses: ./.github/actions/setup-node-with-retry
9999
with:
100100
node-version: ${{ matrix.node-version }}
101101
# TODO: Re-enable cache when Node.js 22 V8 bug is fixed

.github/workflows/playwright.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
ruby-version: '3.3'
5050
bundler-cache: true
5151

52-
- uses: actions/setup-node@v4
52+
- uses: ./.github/actions/setup-node-with-retry
5353
with:
5454
node-version: '20'
5555
cache: 'yarn'

.github/workflows/pro-integration-tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
bundler: 2.5.4
9494

9595
- name: Setup Node
96-
uses: actions/setup-node@v4
96+
uses: ./.github/actions/setup-node-with-retry
9797
with:
9898
node-version: 22
9999
cache: yarn
@@ -189,7 +189,7 @@ jobs:
189189
bundler: 2.5.4
190190

191191
- name: Setup Node
192-
uses: actions/setup-node@v4
192+
uses: ./.github/actions/setup-node-with-retry
193193
with:
194194
node-version: 22
195195
cache: yarn
@@ -386,7 +386,7 @@ jobs:
386386
bundler: 2.5.4
387387

388388
- name: Setup Node
389-
uses: actions/setup-node@v4
389+
uses: ./.github/actions/setup-node-with-retry
390390
with:
391391
node-version: 22
392392
cache: yarn

.github/workflows/pro-lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
bundler: 2.5.4
9292

9393
- name: Setup Node
94-
uses: actions/setup-node@v4
94+
uses: ./.github/actions/setup-node-with-retry
9595
with:
9696
node-version: 22
9797
cache: yarn

.github/workflows/pro-test-package-and-gem.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
bundler: 2.5.4
9494

9595
- name: Setup Node
96-
uses: actions/setup-node@v4
96+
uses: ./.github/actions/setup-node-with-retry
9797
with:
9898
node-version: 22
9999
cache: yarn
@@ -194,7 +194,7 @@ jobs:
194194
persist-credentials: false
195195

196196
- name: Setup Node
197-
uses: actions/setup-node@v4
197+
uses: ./.github/actions/setup-node-with-retry
198198
with:
199199
node-version: 22
200200
cache: yarn

0 commit comments

Comments
 (0)