{"record":{"id":"9e06e14415b4f495","repo":"withastro/astro","slug":"unable-to-resolve-specifier","errorCode":null,"errorMessage":"Unable to resolve [${specifier}]","messagePattern":"Unable to resolve \\[(.+?)\\]","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/environment/production.ts","lineNumber":78,"sourceCode":"\tmanifest: SSRManifest,\n\trouteData: RouteData,\n): Promise<ComponentInstance> {\n\tconst module = await getModuleForRoute(manifest, routeData);\n\treturn module.page();\n}\n\n/**\n * The production / bundled environment — the default when nothing is\n * registered. A stateless module constant derived from the manifest alone.\n */\nexport const productionEnvironment: RenderEnvironment = {\n\tname: 'production',\n\truntimeMode: 'production',\n\tdefaultStreaming: () => true,\n\n\tasync resolve(manifest: SSRManifest, specifier: string): Promise<string> {\n\t\tif (!(specifier in manifest.entryModules)) {\n\t\t\tthrow new Error(`Unable to resolve [${specifier}]`);\n\t\t}\n\t\tconst bundlePath = manifest.entryModules[specifier];\n\t\tif (bundlePath.startsWith('data:') || bundlePath.length === 0) {\n\t\t\treturn bundlePath;\n\t\t} else {\n\t\t\treturn createAssetLink(bundlePath, manifest.base, manifest.assetsPrefix);\n\t\t}\n\t},\n\n\tasync headElements(manifest: SSRManifest, routeData: RouteData): Promise<HeadElements> {\n\t\tconst { assetsPrefix, base } = manifest;\n\t\tconst routeInfo = manifest.routes.find((route) => route.routeData.route === routeData.route);\n\t\t// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.\n\t\tconst links = new Set<never>();\n\t\tconst scripts = new Set<SSRElement>();\n\t\tconst styles = createStylesheetElementSet(routeInfo?.styles ?? [], base, assetsPrefix);\n\n\t\tfor (const script of routeInfo?.scripts ?? []) {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/withastro/astro/blob/52e6c34790cc8ac4e69e6135ace06049867e5c4a/packages/astro/src/core/environment/production.ts#L60-L96","documentation":"`productionEnvironment.resolve` maps an entry specifier (for example a client script or style entry emitted during build) through `manifest.entryModules` to its bundled path, then turns that into an asset link honoring `base` and `assetsPrefix`. If the specifier is not a key in `entryModules`, it throws `Unable to resolve [<specifier>]` — the requested entry was never emitted into this build's manifest.","triggerScenarios":"Code or an integration calling `environment.resolve(manifest, specifier)` for an entry that build did not register (conditionally emitted scripts, filtered routes); server bundle and client assets deployed from different builds so the manifest lacks the entry; a typo'd specifier in custom integration code.","commonSituations":"Partial deploys where `_astro` client assets and the server manifest mismatch; custom renderers/integrations resolving hand-constructed specifiers; asset manifest pruned by post-processing.","solutions":["Rebuild and redeploy server + client output together so `entryModules` matches the assets on disk.","Grep the built SSR manifest for the specifier to confirm whether the build emitted it at all.","If writing an integration, only resolve specifiers that were registered during the same build; guard unknown ones.","Check that conditional emission (route filters, `output` flags) did not skip the entry your code unconditionally resolves."],"exampleFix":"// before — resolving an entry the build never emitted\nconst url = await env.resolve(manifest, 'src/scripts/quantum.js'); // throws\n\n// after — only resolve entries present in the manifest\nif ('src/scripts/quantum.js' in manifest.entryModules) {\n  const url = await env.resolve(manifest, 'src/scripts/quantum.js');\n}","handlingStrategy":"type-guard","validationCode":"// Before resolving an asset entry, confirm the build emitted it\nif (!('src/scripts/quantum.js' in manifest.entryModules)) {\n  return '/fallback.js';\n}\nconst url = await env.resolve(manifest, 'src/scripts/quantum.js');","typeGuard":"function hasEntry(\n  manifest: { entryModules: Record<string, string> },\n  specifier: string,\n): specifier is keyof typeof manifest.entryModules & string {\n  return specifier in manifest.entryModules;\n}","tryCatchPattern":"try {\n  const url = await env.resolve(manifest, specifier);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Unable to resolve [')) {\n    return fallbackAssetUrl(specifier);\n  }\n  throw err;\n}","preventionTips":["Deploy server bundle and client assets from the same build, atomically.","In integrations, only resolve specifiers that were registered during the current build.","Watch conditional emission (route filters, output mode) when code resolves entries unconditionally."],"tags":["internal","ssr","assets","deploy"],"backgroundTag":"missing-build-manifest-entry","analyzedSha":"52e6c34790cc8ac4e69e6135ace06049867e5c4a","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}