withastro/astro · error · AstroError
NoManifestAvailableError
NoManifestAvailableError
Error message
`new FetchState(request)` was called outside of an Astro server, so no manifest is available.
What it means
The public `new FetchState(request)` (astro/fetch) resolves static, build-time data via getAmbientManifest(): the manifest explicitly registered with setAmbientManifest, else the virtual manifest module bundled into every Astro-built server. When neither exists, AstroErrorData.NoManifestAvailable is thrown — the constructor ran outside an Astro server, so no routes, directives, or settings are known.
Source
Thrown at packages/astro/src/core/manifest/ambient.ts:36
/**
* Registers a manifest for environments where `virtual:astro:manifest` cannot
* resolve (plain Node: unit tests, embedders). Internal API — deliberately not
* exported from any public entrypoint.
* Pass `undefined` to clear (test teardown).
*/
export function setAmbientManifest(manifest: SSRManifest | undefined): void {
registered = manifest;
}
/**
* The ambient manifest: the explicitly registered one, else the virtual
* module's. Throws lazily when neither is available, so merely importing a
* module that uses this never fails — only actually handling a request does.
*/
export function getAmbientManifest(): SSRManifest {
const manifest = registered ?? viteManifest;
if (!manifest) {
throw new AstroError(NoManifestAvailable);
}
return manifest;
}
/** The ambient manifest if one is available, else `undefined`. Never throws. */
export function tryGetAmbientManifest(): SSRManifest | undefined {
return registered ?? viteManifest;
}
View on GitHub (pinned to 52e6c34790)
Solutions
- Only create FetchState inside a request handled by an Astro-built server (the built entry or astro dev)
- For custom hosts, register the SSR manifest first with setAmbientManifest(...) from the manifest module before any request
- In tests, import the built server entry (dist/server/entry.mjs) or use Astro's test utilities instead of constructing state by hand
Example fix
// before — plain node script, no server
import { FetchState } from 'astro/fetch';
const state = new FetchState(new Request('http://localhost/page'));
// after — go through the built server's handler
import { handler } from './dist/server/entry.mjs';
const response = await handler(new Request('http://localhost/page')); Defensive patterns
Strategy: try-catch
Try / catch
try {
const state = new FetchState(request);
} catch (err) {
if (err instanceof Error && /no manifest is available/i.test(err.message)) {
throw new Error('FetchState must be created inside an Astro-built server (built entry or astro dev)', { cause: err });
}
throw err;
} Prevention
- Only construct FetchState within a request handled by the Astro-built server
- Custom hosts must register the SSR manifest (setAmbientManifest) before the first request
- In tests, import the built server entry (dist/server/entry.mjs) instead of constructing state directly
When it happens
Trigger: Constructing FetchState directly in a plain Node script, a unit test, or an unbundled import of server code where the virtual manifest module was never loaded and nothing called setAmbientManifest; a custom host importing the handler modules outside the built entry.
Common situations: Unit-testing astro/fetch handler functions in isolation; running the server entry with a custom loader that skips Vite's virtual modules; an integration that spins up its own request handling instead of reusing the built dist/server/entry.mjs.
Related errors
- Astro couldn't find the correct page to render, probably bec
- Could not find server component name ${componentPath}
- Unexpectedly unable to find a component instance for route $
- Astro couldn't find the correct page to render, probably bec
- FetchState not found on APIContext. `next(payload)` rewrites
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/b9ef070df970805d.
Report an issue: GitHub.