{"record":{"id":"8e0cbddd03bba46a","repo":"withastro/astro","slug":"astrojs-node-could-not-find-the-server-director","errorCode":null,"errorMessage":"[@astrojs/node] Could not find the server directory \"${serverFolder}\" by walking up from \"${import.meta.url}\". This can happen when the server entry point is bundled into a single file (e.g. with esbuild) so that import.meta.url no longer contains the original \"${serverFolder}\" path segment. When bundling the server entry, make sure the output path contains a \"${serverFolder}\" directory segment, or avoid bundling the server entry entirely.","messagePattern":"\\[@astrojs/node\\] Could not find the server directory \"(.+?)\" by walking up from \"(.+?)\"\\. This can happen when the server entry point is bundled into a single file \\(e\\.g\\. with esbuild\\) so that import\\.meta\\.url no longer contains the original \"(.+?)\" path segment\\. When bundling the server entry, make sure the output path contains a \"(.+?)\" directory segment, or avoid bundling the server entry entirely\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/integrations/node/src/shared.ts","lineNumber":37,"sourceCode":"export function resolveClientDir(options: Options) {\n\t// options.client and options.server are file:// URLs set at build time\n\t// e.g., \"file:///project/dist/client/\" and \"file:///project/dist/server/\"\n\tconst clientURLRaw = new URL(options.client);\n\tconst serverURLRaw = new URL(options.server);\n\n\t// Calculate relative path from server to client (e.g., \"../client\")\n\t// This relative path is stable regardless of where the build output is deployed\n\tconst rel = path.relative(url.fileURLToPath(serverURLRaw), url.fileURLToPath(clientURLRaw));\n\n\t// Find the server entry folder by walking up from this file's location\n\t// We need to find the actual runtime location, not the build-time paths\n\tconst serverFolder = path.basename(options.server);\n\tlet serverEntryFolderURL = path.dirname(import.meta.url);\n\tlet previous = '';\n\twhile (!serverEntryFolderURL.endsWith(serverFolder)) {\n\t\t// Guard against infinite loop\n\t\tif (serverEntryFolderURL === previous) {\n\t\t\tthrow new Error(\n\t\t\t\t`[@astrojs/node] Could not find the server directory \"${serverFolder}\" ` +\n\t\t\t\t\t`by walking up from \"${import.meta.url}\". This can happen when the server ` +\n\t\t\t\t\t`entry point is bundled into a single file (e.g. with esbuild) so that ` +\n\t\t\t\t\t`import.meta.url no longer contains the original \"${serverFolder}\" path segment. ` +\n\t\t\t\t\t`When bundling the server entry, make sure the output path contains a ` +\n\t\t\t\t\t`\"${serverFolder}\" directory segment, or avoid bundling the server entry entirely.`,\n\t\t\t);\n\t\t}\n\t\tprevious = serverEntryFolderURL;\n\t\tserverEntryFolderURL = path.dirname(serverEntryFolderURL);\n\t}\n\n\t// Resolve the client directory by applying the relative path to the runtime server location\n\tconst serverEntryURL = serverEntryFolderURL + '/entry.mjs';\n\tconst clientURL = new URL(appendForwardSlash(rel), serverEntryURL);\n\treturn url.fileURLToPath(clientURL);\n}\n","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/integrations/node/src/shared.ts#L19-L55","documentation":"Thrown by @astrojs/node's `shared.ts` when it cannot locate the server output directory (`options.server` basename, e.g. `server`) by walking up the directory tree from `import.meta.url`. The relative path from server to client assets is computed from this folder; if the path segment is missing the runtime cannot resolve static assets.","triggerScenarios":"Bundling the server entry into a single flat file (esbuild/webpack/ncc) so `import.meta.url` no longer contains a `server/` directory segment. Deploying to a serverless runtime that flattens the output layout. Renaming the build output directory away from `server`.","commonSituations":"Wrapping the built Node adapter output with esbuild `--bundle`. Using a platform bundler (e.g. Vercel/Netlify functions build) that collapses `dist/server/` into one file. Moving files post-build without preserving the `server` folder name.","solutions":["Stop bundling the @astrojs/node server entry into a single file; deploy `dist/` as a directory tree.","If you must bundle, ensure the output path still contains a `server` directory segment (e.g. `dist/server/entry.js`).","Keep the default `build.server` directory name (`server`) so the basename walk succeeds."],"exampleFix":"// before: esbuild bundles to dist/entry.mjs (no server/ segment)\nesbuild dist/server/entry.mjs --bundle --outfile=dist/entry.mjs\n// after: preserve the server directory\nesbuild dist/server/entry.mjs --bundle --outfile=dist/server/entry.mjs","handlingStrategy":"validation","validationCode":"import { fileURLToPath } from 'node:url';\nconst serverSeg = path.basename(options.server);\nif (!fileURLToPath(import.meta.url).includes(path.sep + serverSeg + path.sep)) {\n  console.warn('Server entry bundled flat; asset resolution may fail.');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Deploy the Node adapter output as a directory tree, not a single bundled file.","If bundling, preserve a `server/` segment in the output path.","Avoid post-build file flattening scripts."],"tags":["node-adapter","bundling","deployment","asset-resolution"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}