stablyai/orca · error
Installed launcher did not preserve a running script failure
Error message
Installed launcher did not preserve a running script failure
What it means
This assertion is part of verifyInstalledLauncher, which validates the Claude agent-hook launcher that Electron installs into ~/.claude/settings.json. After writing a deliberately-failing hook script (exit 7) at $HOME/.orca/agent-hooks/claude-hook.sh, it runs the installed launcher and expects the launcher to propagate that non-zero exit AND to forward the large stdin payload without EPIPE/stdin errors. Failure means the launcher swallowed the child's exit code or dropped/broke the stdin pipe to the child.
Source
Thrown at config/scripts/verify-agent-hook-stdin-lifecycle.mjs:348
try {
const missingResult = await runShell(
command,
payload,
withoutOrcaEnvironment({ HOME: scratch })
)
assertSuccessfulWrite(missingResult, 'installed missing-script launcher')
const failingPath = join(scratch, '.orca', 'agent-hooks', 'claude-hook.sh')
mkdirSync(join(scratch, '.orca', 'agent-hooks'), { recursive: true })
writeFileSync(failingPath, '#!/bin/sh\ncat >/dev/null\nexit 7\n', 'utf8')
chmodSync(failingPath, 0o755)
const failingResult = await runShell(
command,
payload,
withoutOrcaEnvironment({ HOME: scratch })
)
if (failingResult.exitCode !== 7 || failingResult.stdinErrors.length > 0) {
throw new Error('Installed launcher did not preserve a running script failure')
}
} finally {
rmSync(scratch, { recursive: true, force: true })
}
}
async function main() {
const args = parseArgs(process.argv.slice(2))
const payload = JSON.stringify({
hook_event_name: 'PostToolUse',
tool_name: 'shell',
tool_output: 'x'.repeat(1_200_000)
})
const scripts = readGeneratedScripts(args.home, args.minMtime)
await verifyNoOpWrites(scripts, args.home, payload)
await verifyClaudeDevinSkip(scripts, args.home, payload)
await verifyForwarding(scripts, args.home, payload)
await verifyInstalledLauncher(args.home, payload)View on GitHub (pinned to 1136503c6a)
Solutions
- Inspect the installed command string in ~/.claude/settings.json and confirm it forwards stdin to the hook and exits with the hook's status (no `|| exit 0`, no `</dev/null`).
- Reinstall the launcher from a current Electron build (`orca` settings write) so the guarded shim is regenerated, then rerun verify-agent-hook-stdin-lifecycle.mjs.
- If stdinErrors is non-empty, check the launcher isn't redirecting stdin away from the child — the fix is to let the child inherit the launcher's stdin.
Example fix
# before (launcher masks failure)
if [ -f "$HOME/.orca/agent-hooks/claude-hook.sh" ]; then
"$HOME/.orca/agent-hooks/claude-hook.sh" || true
fi
# after (propagate exit + keep stdin connected)
if [ -f "$HOME/.orca/agent-hooks/claude-hook.sh" ] && [ -r "$HOME/.orca/agent-hooks/claude-hook.sh" ]; then
"$HOME/.orca/agent-hooks/claude-hook.sh"
else
{ command -p cat >/dev/null; } 2>/dev/null
fi Defensive patterns
Strategy: validation
Validate before calling
// Validate the installed launcher propagates exit + stdin before the full suite.
const probe = '#!/bin/sh\ncat >/dev/null\nexit 7\n'
writeFileSync(failingPath, probe, 'utf8')
chmodSync(failingPath, 0o755)
const r = await runShell(command, payload, env)
if (r.exitCode !== 7) throw new Error(`launcher exit not propagated: ${r.exitCode}`)
if (r.stdinErrors.length > 0) throw new Error(`launcher broke stdin: ${r.stdinErrors.join(';')}`) Prevention
- Keep the installed launcher shim's `if [ -f ... ] && [ -r ... ]` shape intact so stdin forwarding and exit propagation are preserved.
- Never redirect the hook's stdin (`</dev/null`) in the launcher.
- Re-run verify-agent-hook-stdin-lifecycle.mjs after any change to the launcher template.
When it happens
Trigger: Invoked when failingResult.exitCode !== 7 OR failingResult.stdinErrors.length > 0 at line 347. This happens if the installed launcher masks the hook's exit code (e.g. always exits 0, or `|| true`), or if it closes stdin before the hook reads it (broken pipe / SIGPIPE) so that node's child.stdin emits an 'error' event captured in stdinErrors.
Common situations: A regression in the Electron-installed launcher template (the guarded `if [ -f ... ] && [ -r ... ]` shim) that changes how it forwards stdin or exit status; running the verifier against an older Electron home whose launcher predates stdin-safe forwarding; a shell that handles SIGPIPE differently.
Related errors
- [plain-node-entry-guard] "${entryName}" reaches chunk "${chu
- Electron did not expose GC; keep --js-flags=--expose-gc in t
- Electron trial failed (${result.error?.message ?? result.sig
- Electron trial did not report a result (status ${result.stat
- Electron trial exhausted launcher attempts
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/e39d5a9104917423.
Report an issue: GitHub.