withastro/astro · error · AstroError
The server entrypoint
Error message
The server entrypoint ${fileURLToPath(preview.serverEntrypoint)} does not exist. Have you ran a build yet? What it means
astro preview serves the result of the last astro build. The Node adapter imports the server entrypoint from disk and, when Node fails with ERR_MODULE_NOT_FOUND whose url matches preview.serverEntrypoint, it reports the missing file path and points you at running a build first.
Solutions
- Run astro build, then astro preview
- Confirm the entry file exists at the reported path (default dist/server/entry.mjs)
- Rebuild after changing outDir, build.server, or the adapter so preview.serverEntrypoint matches the fresh output
Example fix
# before astro preview # after astro build && astro preview
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync } from 'node:fs';
const entry = 'dist/server/entry.mjs';
if (!existsSync(entry)) {
console.error(`Missing ${entry}; run astro build first`);
process.exit(1);
} Prevention
- Chain build and preview: astro build && astro preview
- Keep outDir and build.server identical between build and preview commands
- Treat a missing server entry as a skipped/failed build, not a preview problem
When it happens
Trigger: Running astro preview before astro build; dist/ (or the configured outDir) deleted or never created; outDir or build.server changed between build and preview so the entry path moved; a build that failed partway.
Common situations: Fresh clone or CI job that runs preview without build; switching adapters without rebuilding; scripts that clean output directories before preview.
Related errors
- The server entrypoint doesn't have a handler. Are you sure…
- [preview] cannot preview your app.
- AdapterSupportOutputMismatch
- [@astrojs/alpinejs] entrypoint
- [@astrojs/node] Could not find the server directory
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/b8b84f7c20c0d2ef.
Report an issue: GitHub.
Appendix: source
Thrown at packages/integrations/node/src/preview.ts:27
const createPreviewServer: CreatePreviewServer = async (preview) => {
let ssrHandler: ServerModule['handler'];
try {
process.env.ASTRO_NODE_AUTOSTART = 'disabled';
const ssrModule: MaybeServerModule = await import(preview.serverEntrypoint.toString());
if (typeof ssrModule.handler === 'function') {
ssrHandler = ssrModule.handler;
} else {
throw new AstroError(
`The server entrypoint doesn't have a handler. Are you sure this is the right file?`,
);
}
} catch (err) {
if (
(err as any).code === 'ERR_MODULE_NOT_FOUND' &&
(err as any).url === preview.serverEntrypoint.href
) {
throw new AstroError(
`The server entrypoint ${fileURLToPath(
preview.serverEntrypoint,
)} does not exist. Have you ran a build yet?`,
);
} else {
throw err;
}
}
// If the user didn't specify a host, it will already have been defaulted to
// "localhost" by getResolvedHostForHttpServer in astro core/preview/util.ts.
// The value `undefined` actually means that either the user set `options.server.host`
// to `true`, or they passed `--host` without an argument. In that case, we
// should listen on all IPs.
const host = process.env.HOST ?? preview.host ?? '0.0.0.0';
const port = preview.port ?? 4321;
const server = createServer(ssrHandler, host, port);
View on GitHub (pinned to 52e6c34790)