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

  1. Only create FetchState inside a request handled by an Astro-built server (the built entry or astro dev)
  2. For custom hosts, register the SSR manifest first with setAmbientManifest(...) from the manifest module before any request
  3. 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

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


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/b9ef070df970805d. Report an issue: GitHub.