stablyai/orca · error · Error
Sidecar did not exit after graceful IPC close
Error message
Sidecar did not exit after graceful IPC close
What it means
verifyGracefulClose disconnects the sidecar's IPC channel and expects the sidecar process to exit within PROCESS_EXIT_TIMEOUT_MS. If it does not, the sidecar is hanging on a non-IPC reference (open handle, blocked syscall) instead of reacting to channel close — a graceful-shutdown regression. The helper-exit check (119) runs only after this passes.
Source
Thrown at config/scripts/macos-computer-helper-owner-loss-benchmark.mjs:313
latencies.push(performance.now() - requestStartedAt)
}
const totalMs = performance.now() - startedAt
return {
totalMs,
requestsPerSecond: (ACTIVE_REQUEST_COUNT * 1_000) / totalMs,
medianLatencyMs: median(latencies),
p95LatencyMs: percentile(latencies, 0.95),
maxLatencyMs: Math.max(...latencies)
}
}
async function verifyGracefulClose() {
const { sidecar, helper } = await startAuthenticatedSession()
try {
const startedAt = performance.now()
sidecar.child.disconnect()
if (!(await waitForChildExit(sidecar.child, PROCESS_EXIT_TIMEOUT_MS))) {
throw new Error('Sidecar did not exit after graceful IPC close')
}
const helperExitMs = await waitForProcessExit(helper, PROCESS_EXIT_TIMEOUT_MS)
if (helperExitMs === null) {
throw new Error('Helper did not exit after graceful owner close')
}
return Math.round(performance.now() - startedAt)
} finally {
sidecar.child.kill('SIGKILL')
await stopProcess(helper)
}
}
async function runInternalTrial(expectation) {
let sidecar
let helper
let invalidPeer
let invalidPeerRejected = false
try {View on GitHub (pinned to 1136503c6a)
Solutions
- Inspect the sidecar for lingering handles (node --trace-warnings / process._getActiveHandles) when run standalone.
- Confirm the sidecar's IPC disconnect handler still triggers exit (e.g. calls server.close/process.exit).
- If the helper genuinely needs more time, raise PROCESS_EXIT_TIMEOUT_MS — but only after ruling out a real hang.
- Check that stdio to the parent is closed/ignored so it does not keep the loop alive.
Example fix
// before
sidecar.child.disconnect()
if (!(await waitForChildExit(sidecar.child, PROCESS_EXIT_TIMEOUT_MS))) {
throw new Error('Sidecar did not exit after graceful IPC close')
}
// after
sidecar.child.disconnect()
if (!(await waitForChildExit(sidecar.child, PROCESS_EXIT_TIMEOUT_MS))) {
const handles = await tryGetActiveHandles(sidecar)
throw new Error(`Sidecar did not exit after graceful IPC close; activeHandles=${JSON.stringify(handles)}`)
} Defensive patterns
Strategy: retry
Validate before calling
const exited = await waitForChildExit(sidecar.child, PROCESS_EXIT_TIMEOUT_MS)
if (!exited) {
throw new Error(`Sidecar still alive ${PROCESS_EXIT_TIMEOUT_MS}ms after disconnect; inspect active handles`)
} Type guard
const hasExited = (child) => child.exitCode !== null || child.signalCode !== null
Try / catch
try {
await verifyGracefulClose()
} catch (e) {
if (/Sidecar did not exit/.test(e.message)) { /* SIGTERM fallback then re-check */ sidecar.child.kill('SIGTERM'); await waitForChildExit(sidecar.child, PROCESS_EXIT_TIMEOUT_MS) }
else throw e
} Prevention
- Ensure the sidecar's IPC disconnect handler calls process.exit/server.close.
- Avoid unref'd-but-referenced timers/sockets that keep the event loop alive.
- Close/ignore stdio to the parent so it doesn't hold the loop open.
When it happens
Trigger: The sidecar ignores the IPC 'disconnect' event, holds a keep-alive handle (timer/socket/stdio) that prevents exit, or is blocked in a synchronous operation when disconnect fires.
Common situations: A code change that added an unref'd-but-still-referenced timer, an open file/socket keeping the event loop alive, or a regression in the disconnect handler that previously called process.exit.
Related errors
- Helper did not exit after graceful owner close
- [plain-node-entry-guard] daemon-entry.js did not exit within
- Could not read watchdog child RSS for PID ${pid}
- Could not read physical footprint for PIDs ${pids.join(', ')
- Could not read CPU time for PID ${pid}
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/ce5fa26a1150f583.
Report an issue: GitHub.