Skip to content

Retry gVisor agent startup crashes once before failing#6514

Merged
lpcox merged 3 commits into
mainfrom
copilot/fix-gvisor-agent-runtime-crash
Jul 23, 2026
Merged

Retry gVisor agent startup crashes once before failing#6514
lpcox merged 3 commits into
mainfrom
copilot/fix-gvisor-agent-runtime-crash

Conversation

Copilot AI commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Under sandbox.agent.runtime: gvisor, the agent occasionally dies before doing any work with native Node/V8 crashes (SIGABRT/exit 134 and SIGSEGV/exit 139). The same workloads were stable on runc and docker-sbx, so this change focuses on recovering the known gVisor-specific hard-crash path instead of changing normal agent execution.

  • Runtime-scoped recovery

    • Extend the Docker agent execution path to accept containerRuntime.
    • Treat gVisor startup crashes as a recoverable launch failure, not a terminal workflow failure.
  • One-shot retry for native crash exits

    • In runAgentCommand(), retry the agent container once when the gVisor runtime exits with:
      • 134 (SIGABRT)
      • 139 (SIGSEGV)
    • Restart uses docker start awf-agent, then reattaches log streaming and waits for the new exit status.
    • Non-gVisor runtimes keep the existing behavior.
  • Log continuity

    • Reattach logs with docker logs --since <timestamp> -f awf-agent on the retry path to avoid replaying the full first-attempt log stream.
  • CLI wiring

    • Pass the configured runtime from the main workflow path into the agent command runner so the retry behavior is enabled only for compose-managed gVisor agents.
if (isGvisorRuntime(containerRuntime) && (exitCode === 134 || exitCode === 139)) {
  await execa('docker', ['start', AGENT_CONTAINER_NAME], { ... });
  exitCode = await executeAgentAttempt(new Date().toISOString());
}

Copilot AI changed the title [WIP] Fix gVisor agent runtime crash at startup Retry gVisor agent startup crashes once before failing Jul 22, 2026
Copilot finished work on behalf of lpcox July 22, 2026 23:50
Copilot AI requested a review from lpcox July 22, 2026 23:50
@lpcox
lpcox marked this pull request as ready for review July 22, 2026 23:51
Copilot AI review requested due to automatic review settings July 22, 2026 23:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds one-shot recovery for gVisor agent crashes caused by SIGABRT or SIGSEGV.

Changes:

  • Retries gVisor exits 134/139 once.
  • Preserves log continuity using docker logs --since.
  • Passes the configured runtime into agent execution.
Show a summary per file
File Description
src/container-lifecycle.ts Implements gVisor crash retry and log reattachment.
src/run-agent-command.test.ts Tests retry and runtime scoping.
src/commands/main-action.ts Wires the runtime into agent execution.
src/commands/main-action.test.ts Tests runtime forwarding.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Medium


if (isGvisorRuntime(containerRuntime)) {
for (let attempt = 1; attempt <= MAX_GVISOR_AGENT_RETRIES; attempt++) {
if (!GVISOR_RETRYABLE_AGENT_EXIT_CODES.has(exitCode)) {
stderr: 'inherit',
env: getLocalDockerEnv(),
});
exitCode = await executeAgentAttempt(logsSince);
@lpcox

lpcox commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

…dget

- Add isGvisorStartupCrash() helper: uses docker inspect to measure
  container runtime; only containers that exit within 30s of start
  (GVISOR_STARTUP_CRASH_WINDOW_MS) are considered pure startup crashes
  safe to retry. This prevents a second run when the agent has already
  produced work (files, API calls, etc.).

- Track a single overall deadline (overallDeadlineMs) in runAgentCommand
  before the first attempt. executeAgentAttempt now computes remainingMs
  = overallDeadlineMs - Date.now() on each call. When remainingMs <= 0
  on the retry, the container is stopped immediately and exit code 124 is
  returned, so a gVisor run can never execute beyond the configured
  --agent-timeout total.

- Update existing gVisor retry tests to supply the docker inspect mock
  (short runtime = startup crash).

- Add new test: no retry when container ran past the 30s startup window.
- Add new test: retry returns 124 immediately when overall budget is
  exhausted (verified via Date.now spy).

Copilot AI commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Both review items are addressed in commit a37a5e1:

Startup-crash gating (src/container-lifecycle.ts:316): Added isGvisorStartupCrash(), which calls docker inspect --format '{{.State.StartedAt}} {{.State.FinishedAt}}' to measure actual container runtime. The retry only proceeds when runtimeMs < 30 000 ms (Node/V8 startup window). Containers that ran longer — meaning the agent had time to create files, make API calls, or produce any output — are not restarted.

Single shared deadline (src/container-lifecycle.ts:329): overallDeadlineMs is now computed once at runAgentCommand entry. executeAgentAttempt uses remainingMs = overallDeadlineMs - Date.now() on each invocation; when remainingMs ≤ 0 it stops the container immediately and returns 124. The retry can only use whatever time the first attempt left — the total wall time is bounded by the configured --agent-timeout.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Build Test Suite completed successfully!

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Chroot tests passed! Smoke Chroot - All security and functionality tests succeeded.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🛡️ Smoke Copilot Network Isolation confirmed the egress allowlist is enforced. ✅

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Contribution Check completed successfully!

Contribution check complete: PR #6514 follows the applicable CONTRIBUTING.md guidelines. New gVisor retry functionality includes tests, the PR description is clear and references the related issue, and the files are organized appropriately. No review comment needed.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🔌 Smoke Services — All services reachable! ✅

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🔑 Smoke Copilot PAT PAT auth validated. All systems operational. ✅

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Smoke Claude passed

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

📡 Smoke OTel Tracing completed. All tracing scenarios validated. ✅

@github-actions github-actions Bot added the smoke-copilot-network-isolation Copilot network-isolation egress smoke test label Jul 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🧪 Smoke Test Results

Test Status
GitHub MCP connectivity ✅ (PR data retrieved)
GitHub.com HTTP ✅ 200
File write/read

Overall: PASS

@lpcox

📰 BREAKING: Report filed by Smoke Copilot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Claude Engine Validation

Check Result
API status ✅ PASS
gh check ✅ PASS
File status ✅ PASS

Overall result: PASS

Generated by Smoke Claude for #6514 · 54.3 AIC · ⊞ 3.2K ·
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

🔬 Smoke Test: Copilot PAT Auth

Test Status
GitHub MCP connectivity ✅ (MCP responded; PR filtered by secrecy policy)
GitHub.com HTTP ⚠️ Pre-step data not expanded
File write/read ⚠️ Pre-step data not expanded

Note: Template variables (${{ steps.smoke-data.outputs.* }}) were not expanded — pre-computed test data unavailable. MCP is reachable.
Auth mode: PAT (COPILOT_GITHUB_TOKEN)

Overall: INDETERMINATE (template expansion failure)

🔑 PAT report filed by Smoke Copilot PAT
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke test results

  • Retry gVisor agent startup crashes once before failing
  • Switch Squid image to Alpine to remove Berkeley DB/Sleepycat components
  • fix(security): update vulnerable deps in agent and api-proxy images
  • GitHub query: ✅
  • Browser title: ✅
  • File write/read: ✅
  • Build: ✅
  • Discussion comment: ⚠️ unavailable
  • Overall: PASS

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: API Proxy OpenTelemetry Tracing

Scenario Result Notes
✅ Module Loading Pass otel.js loads successfully; exports: startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled, and internal helpers
✅ Test Suite Pass 59 tests passed across otel.test.js and otel-fanout.test.js (2 suites)
✅ Env Var Forwarding Pass src/services/api-proxy-env-config.ts forwards OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, GITHUB_AW_OTEL_TRACE_ID, GITHUB_AW_OTEL_PARENT_SPAN_ID, and OTEL_SERVICE_NAME to the api-proxy container
✅ Token Tracker Integration Pass onUsage callback exists in token-tracker-http.js as the OTEL hook point
✅ Graceful Degradation Pass isEnabled export confirmed; module loads without error when OTEL is not configured

All 5 scenarios passed. OTEL tracing integration is working correctly.

📡 OTel tracing validated by Smoke OTel Tracing
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.13 ✅ YES
Node.js v24.18.0 v22.23.1 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ FAILED — Node.js version mismatch (host: v24.18.0, chroot: v22.23.1).

Tested by Smoke Chroot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results

  • GitHub MCP Testing: ❌ (Bridge works, but data filtered by secrecy policy)
  • GitHub.com Connectivity: ❌ (Connection refused/DNS failure)
  • File Writing Testing: ✅
  • Bash Tool Testing: ✅

Overall status: FAIL

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • localhost

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

💎 Faceted by Smoke Gemini
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot BYOK (Direct) Mode

  • ✅ GitHub MCP connectivity
  • ✅ GitHub.com connectivity (HTTP 200)
  • ✅ File write/read test
  • ✅ BYOK inference test

Status: PASS
Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY) via api-proxy → api.githubcopilot.com
@lpcox

🔑 BYOK report filed by Smoke Copilot BYOK
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Services Connectivity — ❌ FAIL

Check Result
Redis PING ❌ Name resolution failed
PostgreSQL pg_isready ❌ No response
PostgreSQL SELECT 1 ❌ Name resolution failed

host.docker.internal is not resolvable in this environment. All checks failed.

🔌 Service connectivity validated by Smoke Services
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx All passed ✅ PASS
Node.js execa All passed ✅ PASS
Node.js p-limit All passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Notes:

  • Java: Maven local repository was owned by root; used -Dmaven.repo.local=/tmp/gh-aw/agent/m2-repo workaround to resolve LocalRepositoryNotAccessibleException
  • Deno: Initial clone was delayed; re-cloned successfully and all tests passed

Generated by Build Test Suite for #6514 · 55.2 AIC · ⊞ 8.2K ·
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

@lpcox

Smoke test results:

  • GitHub MCP Testing: ❌
  • GitHub.com connectivity: ✅
  • File write/read test: ✅
  • BYOK inference test: ✅

Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw)

Overall: FAIL

🔑 BYOK (AOAI api-key) report filed by Smoke Copilot BYOK AOAI (api-key)
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

@lpcox
GitHub MCP connectivity: ❌ (filtered by policy)
GitHub.com HTTP: ✅
File write/read: ❌ (SMOKE_FILE_PATH unset)
BYOK inference: ✅
Running in direct BYOK mode (AWF_AUTH_TYPE=github-oidc + AWF_AUTH_AZURE_* + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw) authenticated via Microsoft Entra
Overall: FAIL

🪪 BYOK (AOAI Entra) report filed by Smoke Copilot BYOK AOAI (Entra)
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smoke Test: Docker Sbx Validation

Test Result
GitHub MCP connectivity ⚠️ Filtered by secrecy policy
GitHub.com HTTP connectivity ⚠️ Template vars unresolved
File write/read ⚠️ Template vars unresolved

Overall: ⚠️ INCONCLUSIVE — Pre-computed test data was not injected (raw ${{ steps.smoke-data.outputs.* }} expressions in prompt). Smoke test infrastructure issue, not a code failure.

📰 BREAKING: Report filed by Smoke Docker Sbx
Add label ready-for-aw to run again

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gVisor (runsc) agent runtime: Copilot CLI Node/V8 crashes at startup (~8%) — SIGABRT StringBytes::Encode & SIGSEGV

3 participants