{"record":{"id":"141020721c81003d","repo":"withastro/astro","slug":"timeout-141020","errorCode":null,"errorMessage":"Timeout","messagePattern":"Timeout","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/upgrade/src/shell.ts","lineNumber":72,"sourceCode":"\ttry {\n\t\tconst [resolvedCommand, resolvedFlags] = resolveCommand(command, flags);\n\t\tchild = spawn(resolvedCommand, resolvedFlags, {\n\t\t\tcwd: opts.cwd,\n\t\t\tstdio: opts.stdio,\n\t\t\ttimeout: opts.timeout,\n\t\t});\n\t\tconst done = new Promise<void>((resolve, reject) => {\n\t\t\tchild.once('error', reject);\n\t\t\tchild.once('close', () => resolve());\n\t\t});\n\t\t[stdout, stderr] = await Promise.all([text(child.stdout), text(child.stderr), done]);\n\t} catch (e) {\n\t\tconst message = e instanceof Error ? e.message : stderr || 'Unknown error';\n\t\tthrow new Error(message);\n\t}\n\tconst { exitCode } = child;\n\tif (exitCode === null) {\n\t\tthrow new Error('Timeout');\n\t}\n\tif (exitCode !== 0) {\n\t\tthrow new Error(stderr || stdout || `Process exited with code ${exitCode}`);\n\t}\n\treturn { stdout, stderr, exitCode };\n}\n","sourceCodeStart":54,"sourceCodeEnd":79,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/upgrade/src/shell.ts#L54-L79","documentation":"Thrown by the `shell()` helper in the upgrade tool after the spawned child process has emitted `close` but Node reports `exitCode === null`. In the upgrade tool, `exitCode` is null when the process was killed by the `timeout` option passed to `spawn` (a SIGTERM kill leaves exitCode null). It signals the subprocess did not finish within the configured timeout window.","triggerScenarios":"A command invoked via `shell()` (e.g. a package manager install/git fetch) takes longer than the `opts.timeout` value passed to spawn; the process hangs on a prompt or network stall and gets killed; on Windows the .exe shim hangs.","commonSituations":"Slow or metered network during `pnpm install`/`npm install` run by the upgrade command; a global npm/pnpm mirror with high latency; the spawned command is waiting on interactive input that never arrives; a very large dependency tree install.","solutions":["Increase the timeout: the caller passes `opts.timeout` to `shell()` — raise it (or remove it) for long-running install commands.","Pre-warm the install cache (`pnpm fetch` or `npm ci` against a lockfile) so the spawned install is faster.","Fix the registry/mirror to a faster endpoint and ensure network is stable.","If the spawned command prompts, run it manually once to satisfy the prompt, or pass non-interactive flags (e.g. `--yes`, `--no-interactivity`)."],"exampleFix":"// before\nchild = spawn(resolvedCommand, resolvedFlags, {\n  cwd: opts.cwd,\n  stdio: opts.stdio,\n  timeout: opts.timeout,\n});\n\n// after — propagate a richer signal so callers know it was a timeout\nif (exitCode === null) {\n  throw new Error(`Timeout after ${opts.timeout ?? 'n/a'}ms running ${command}`);\n}","handlingStrategy":"retry","validationCode":"// Choose a timeout proportional to the command's expected cost\nfunction timeoutForCommand(cmd: string): number | undefined {\n  if (/install|fetch/i.test(cmd)) return 10 * 60 * 1000; // 10 min for installs\n  return 60_000;\n}\n// pass shell(cmd, flags, { timeout: timeoutForCommand(cmd) })","typeGuard":"function isTimeoutError(e: unknown): boolean {\n  return e instanceof Error && e.message === 'Timeout';\n}","tryCatchPattern":"try {\n  await shell(cmd, flags, { timeout });\n} catch (e) {\n  if (isTimeoutError(e)) {\n    // retry once with a larger timeout or surface a clear 'install timed out' message\n  } else throw e;\n}","preventionTips":["Pre-warm caches (`pnpm fetch`) so spawned installs finish within the timeout.","Use non-interactive flags so subprocesses never block on prompts.","Pass timeouts proportional to the command's expected runtime.","Run installs against a fast/local registry mirror."],"tags":["subprocess","timeout","upgrade-tool","spawn"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}