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` uses the same lock-file mechanism as `astro dev` but keyed to the `'preview'` role. Before binding it checks `checkExistingServer(root, 'preview')` and refuses to start a second preview server against the same project root. `--force` is supported to kill and replace the prior preview process.

Source

Thrown at packages/astro/src/cli/preview/index.ts:93

		logger.error(
			'SKIP_FORMAT',
			`Unknown command: astro preview ${subcommand}\n\nRun \`astro preview --help\` to see available commands.`,
		);
		process.exit(1);
	}

	const root = pathToFileURL(resolveRoot(flags.root) + '/');
	const existingServer = 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 d081033d5f)

Solutions

  1. Run `astro preview stop` to stop the existing preview server.
  2. Run `astro preview --force` to replace it in one command.
  3. Manually kill the recorded PID and remove the preview lock file in `.astro/` if the process is already dead but the lock is stale.
  4. Verify with `ps -p <PID>` before killing anything.

Example fix

// before
$ astro preview
// after
$ astro preview --force
Defensive patterns

Strategy: validation

Validate before calling

function isPreviewServerRunning(root) {
  const lockPath = join(root, '.astro', 'preview.lock');
  if (!existsSync(lockPath)) return null;
  try {
    const { pid, url } = JSON.parse(readFileSync(lockPath, 'utf-8'));
    if (pid && process.kill(pid, 0)) return { pid, url };
  } catch {}
  return null;
}

Prevention

When it happens

Trigger: Running `astro preview` while a prior `astro preview` for the same root still holds the lock (live PID). Distinct from the dev server lock — a running `astro dev` does not trigger this, only another preview does.

Common situations: A preview server left running after building and starting it in another terminal; CI caching a workspace with a stale preview process; switching between multiple builds and forgetting the previous preview is still serving the old `dist/`.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/98234d2f50872e0f. Report an issue: GitHub.