withastro/astro · error · AstroError

NoMatchingStaticPathFound

NoMatchingStaticPathFound

Error message

A `getStaticPaths()` route pattern was matched, but no matching static path was found for requested path `${pathName}`.

What it means

A dynamic route's pattern matched the requested URL, but getStaticPaths() did not return a params entry matching that URL. For prerendered (or SSR prerender-default) non-internal routes, every reachable URL must be enumerated by getStaticPaths().

Source

Thrown at packages/astro/src/core/render/params-and-props.ts:66

	// During build, the route cache should already be populated.
	// During development, the route cache is filled on-demand and may be empty.
	const staticPaths = await callGetStaticPaths({
		mod,
		route,
		routeCache,
		ssr: serverLike,
		base,
		trailingSlash,
	});

	// The pathname used here comes from the server, which already encoded.
	// Since we decided to not mess up with encoding anymore, we need to decode them back so the parameters can match
	// the ones expected from the users
	const params = getParams(route, pathname);
	const matchedStaticPath = findPathItemByKey(staticPaths, params, route, logger, trailingSlash);
	if (!matchedStaticPath && route.origin !== 'internal' && (serverLike ? route.prerender : true)) {
		throw new AstroError({
			...AstroErrorData.NoMatchingStaticPathFound,
			message: AstroErrorData.NoMatchingStaticPathFound.message(pathname),
			hint: AstroErrorData.NoMatchingStaticPathFound.hint([route.component]),
		});
	}

	if (mod) {
		validatePrerenderEndpointCollision(route, mod, params);
	}

	const props: Props = matchedStaticPath?.props ? { ...matchedStaticPath.props } : {};

	return props;
}

/**
 * When given a route with the pattern `/[x]/[y]/[z]/svelte`, and a pathname `/a/b/c/svelte`,
 * returns the params object: { x: "a", y: "b", z: "c" }.

View on GitHub (pinned to d081033d5f)

Solutions

  1. Ensure getStaticPaths() returns a params object whose values match the requested path.
  2. If the route should handle arbitrary paths at runtime, mark it server-rendered with `export const prerender = false`.
  3. Check for typos or encoding differences between the link and the param value.
  4. Return a 404 intentionally via a custom 404 page instead of letting the unmatched route throw.

Example fix

// before
export async function getStaticPaths() {
  return [
    { params: { slug: 'hello-world' } }
  ];
}
// request to /blog/hello-word (typo) throws

// after — render on demand so unknown slugs don't crash the build
export const prerender = false;
Defensive patterns

Strategy: validation

Validate before calling

// ensure every reachable path is in getStaticPaths
const known = new Set(slugs.map(s => `/blog/${s}`));
if (!known.has(requestedPath)) {
  // return a controlled 404 instead of letting Astro throw
  return new Response('Not found', { status: 404 });
}

Try / catch

try {
  // render the matched static path
} catch (e) {
  if (e instanceof AstroError && e.code === 'NoMatchingStaticPathFound') {
    return new Response(null, { status: 404 });
  }
  throw e;
}

Prevention

When it happens

Trigger: Requesting /blog/99 when getStaticPaths only returned ids 1..10; a typo in the requested path vs. generated params; params case mismatch; getStaticPaths filtering out entries that users can still navigate to; changing data source so fewer paths are generated.

Common situations: Stale links pointing to deleted content; content collection entry removed but still linked; query-param or slug mismatch between generated and requested paths; running in static/hybrid output where unmatched dynamic routes are not server-rendered.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/3284c5f7f3a2a1f1. Report an issue: GitHub.