withastro/astro · error · Error
Timeout
Error message
Timeout
What it means
Thrown by `create-astro`'s `shell()` helper when a spawned child process has `exitCode === null` after the promise settles. A null exit code means the process was killed by a signal or terminated by the spawn timeout rather than exiting normally — most commonly the `timeout` option elapsed and Node killed the process.
Source
Thrown at packages/create-astro/src/shell.ts:71
try {
const [resolvedCommand, resolvedFlags] = resolveCommand(command, flags);
child = spawn(resolvedCommand, resolvedFlags, {
cwd: opts.cwd,
stdio: opts.stdio,
timeout: opts.timeout,
});
const done = new Promise<void>((resolve, reject) => {
child.once('error', reject);
child.once('close', () => resolve());
});
[stdout, stderr] = await Promise.all([text(child.stdout), text(child.stderr), done]);
} catch (e) {
const message = e instanceof Error ? e.message : stderr || 'Unknown error';
throw new Error(message);
}
const { exitCode } = child;
if (exitCode === null) {
throw new Error('Timeout');
}
if (exitCode !== 0) {
throw new Error(stderr || `Process exited with code ${exitCode}`);
}
return { stdout, stderr, exitCode };
}
View on GitHub (pinned to d081033d5f)
Solutions
- Increase or remove the `timeout` option passed to `shell()`.
- Ensure the spawned command is non-interactive (pass `--yes`/`--no-input` flags) so it doesn't block waiting for input.
- Diagnose the slowness (network, disk, mirror) and fix the root cause rather than extending the timeout indefinitely.
Example fix
// before
await shell('npm', ['install'], { timeout: 10_000 });
// after
await shell('npm', ['install', '--no-fund', '--no-audit'], { timeout: 120_000 }); Defensive patterns
Strategy: try-catch
Validate before calling
// Before calling shell(), estimate expected runtime and set timeout comfortably above it.
const EXPECTED_INSTALL_MS = 60_000;
await shell('npm', ['install'], { timeout: EXPECTED_INSTALL_MS * 3 }); Try / catch
try {
await shell(cmd, flags, { timeout: 60_000 });
} catch (e) {
if (e.message === 'Timeout') { /* retry with longer timeout or non-interactive flags */ }
else throw e;
} Prevention
- Set timeouts generously for network-bound commands (install, clone).
- Pass non-interactive flags (--yes, --no-input) so children never block on a prompt.
- Log wall-clock time of each shell() call to size timeouts correctly.
When it happens
Trigger: Calling `shell(command, flags, { timeout: N })` where the command runs longer than N milliseconds. The child is killed by SIGTERM at the timeout boundary; `child.exitCode` remains null (signal kill, not voluntary exit).
Common situations: Running a slow package manager install (`npm install`, `pnpm install`) with a tight timeout during scaffolding. Network-bound git clones exceeding the timeout. A hung interactive prompt blocking the child.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Process exited with code ${exitCode}
- Template ${tmpl} does not exist!
- Unable to download template ${tmpl}
- Unknown error parsing tsconfig.json or jsconfig.json. Could
- ${integration} does not appear to be a valid package name!
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/9751b7fe25c3f6a4.
Report an issue: GitHub.