withastro/astro · error · Error
Another astro preview server is already running. URL
Error message
Another astro preview server is already running.
URL: ${existingServer.url}
PID: ${existingServer.pid}
Run `astro preview stop` to stop it, or use `astro preview --force` to replace it. What it means
`astro preview` reads the preview lock file (`.astro/preview.json` under the project root) and probes the recorded PID before starting. A live preview server is already registered for this root, so the command aborts instead of orphaning `astro preview stop`.
Solutions
- Run `astro preview stop` to stop the existing server, then run `astro preview` again
- Or replace it: `astro preview --force`
- If the recorded PID is dead (or was reused by an unrelated process), delete `.astro/preview.json` in the project root and retry
Example fix
# before astro preview # Another astro preview server is already running. URL: ... PID: ... # after astro preview stop astro preview # or replace directly: astro preview --force
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
function previewServerIsRunning(root) {
const lock = join(root, '.astro', 'preview.json');
if (!existsSync(lock)) return false;
try {
const { pid } = JSON.parse(readFileSync(lock, 'utf8'));
process.kill(pid, 0);
return true;
} catch {
return false;
}
}
if (previewServerIsRunning(root)) {
// run `astro preview stop` (or pass --force) before `astro preview`
} Try / catch
import { spawnSync } from 'node:child_process';
const r = spawnSync('astro', ['preview'], { encoding: 'utf8' });
if (r.status !== 0 && /Another astro preview server is already running/.test(r.stderr)) {
spawnSync('astro', ['preview', 'stop'], { stdio: 'inherit' });
// retry `astro preview` once
} Prevention
- Stop preview servers with `astro preview stop` at the end of verification scripts
- Use `astro preview --force` in automation where replacing a prior server is intended
- Check `.astro/preview.json` in the project root when a start fails unexpectedly — a reused PID can masquerade as a live server
When it happens
Trigger: Running `astro preview` (typically after `astro build`) while another preview server for the same project root is still running — a previous terminal, a detached process, or tooling that started preview earlier.
Common situations: Iterating on production builds and forgetting the previous preview; CI or scripts running preview twice; editor task runners keeping preview alive.
Related errors
- Another astro dev server is already running. URL
- `--ignore-lock` cannot be used together with
- Be sure to follow the
- ConfigNotFound
- Couldn't parse tsconfig.json or jsconfig.json
AI-assisted analysis of withastro/astro@e294953aa8 (2026-08-18).
Data as JSON: /api/errors/98234d2f50872e0f.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/cli/preview/index.ts:146
'This instance is not tracked by `astro preview stop`, `astro preview status`, or `astro preview logs`.',
].join('\n'),
);
}
const inlineConfig = flagsToAstroInlineConfig(flags);
return await previewServer(inlineConfig);
}
const existingServer = await checkExistingServer(root, 'preview');
if (existingServer) {
const message = [
'Another astro preview server is already running.',
'',
` URL: ${existingServer.url}`,
` PID: ${existingServer.pid}`,
'',
`Run \`astro preview stop\` to stop it, or use \`astro preview --force\` to replace it.`,
].join('\n');
throw new Error(message);
}
const inlineConfig = flagsToAstroInlineConfig(flags);
const server = await previewServer(inlineConfig);
const serverUrl = server.urls?.local[0]
? new URL(server.urls.local[0]).origin
: `http://${server.host ?? 'localhost'}:${server.port}`;
writeLockFile(
root,
{
pid: process.pid,
port: server.port,
url: serverUrl,
urls: server.urls,
background: !!process.env.ASTRO_PREVIEW_BACKGROUND,
startedAt: new Date().toISOString(),
},View on GitHub (pinned to e294953aa8)