withastro/astro · error · AstroError

InvalidGetStaticPathsReturn

InvalidGetStaticPathsReturn

Error message

Invalid type returned by `getStaticPaths()`. Expected an `array`, got `${returnType}`.

What it means

getStaticPaths() must return a plain array of { params, props } entry objects. validateGetStaticPathsResult checks Array.isArray on the returned value and throws InvalidGetStaticPathsReturn (with typeof interpolated into the message) when it is anything else — an object map, a string, undefined, a Promise-like that was not awaited, etc. The route params cannot be derived from a non-array shape.

Solutions

  1. Make the function return an array: wrap object values with Object.values(map).map(...) or ensure every code path returns the array.
  2. If getStaticPaths is async, await all async calls before returning (return (await getPosts()).map(...)).
  3. Return [] (empty array) explicitly when the collection is empty, instead of undefined.

Example fix

// before
export async function getStaticPaths() {
  const res = fetch('https://api.example.com/posts'); // missing await
  return res.json().map((p) => ({ params: { slug: p.slug } }));
}

// after
export async function getStaticPaths() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();
  return posts.map((p) => ({ params: { slug: p.slug } }));
}
Defensive patterns

Strategy: type-guard

Type guard

type StaticPath = { params: Record<string, string | undefined>; props?: Record<string, unknown> };

function isStaticPathArray(v: unknown): v is StaticPath[] {
  return (
    Array.isArray(v) &&
    v.every((e) => typeof e === 'object' && e !== null && !Array.isArray(e) && 'params' in e)
  );
}

// const paths = await getStaticPaths();
// if (!isStaticPathArray(paths)) throw new TypeError('getStaticPaths must return { params }[]');

Prevention

When it happens

Trigger: Returning an object keyed by slug (return { 'a': {...}, 'b': {...} }); returning a single entry instead of a list (return { params: { slug: 'a' } }); forgetting await on an async fetch inside getStaticPaths so a Promise leaks; returning undefined because of a missing return in an if-branch; returning a Map or generator.

Common situations: Porting data from a CMS keyed as an object; early-return code paths that forget to return; getStaticPaths declared async but the final .map() chain dropped; returning getCollection(...) directly thinking it is an array.

Related errors


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

Appendix: source

Thrown at packages/astro/src/core/routing/validation.ts:28

		ssr,
		route,
	}: {
		ssr: boolean;
		route: RouteData;
	},
) {
	if ((!ssr || route.prerender) && route.origin !== 'internal' && !mod.getStaticPaths) {
		throw new AstroError({
			...AstroErrorData.GetStaticPathsRequired,
			location: { file: route.component },
		});
	}
}

/** Throw error and log warnings for malformed getStaticPaths() response */
export function validateGetStaticPathsResult(result: GetStaticPathsResult, route: RouteData) {
	if (!Array.isArray(result)) {
		throw new AstroError({
			...AstroErrorData.InvalidGetStaticPathsReturn,
			message: AstroErrorData.InvalidGetStaticPathsReturn.message(typeof result),
			location: {
				file: route.component,
			},
		});
	}

	result.forEach((pathObject) => {
		if ((typeof pathObject === 'object' && Array.isArray(pathObject)) || pathObject === null) {
			throw new AstroError({
				...AstroErrorData.InvalidGetStaticPathsEntry,
				message: AstroErrorData.InvalidGetStaticPathsEntry.message(
					Array.isArray(pathObject) ? 'array' : typeof pathObject,
				),
			});
		}

View on GitHub (pinned to 52e6c34790)