withastro/astro · error · TypeError

Missing parameter

Error message

Missing parameter: ${part.content}

What it means

`getRouteGenerator` composes concrete paths from a params object: every dynamic (non-spread) route part must find a defined value in `params`, or it throws `TypeError: Missing parameter: <name>`. It is reached mainly through `stringifyParams`, which keys `getStaticPaths()` results — and note that `stringifyParams` drops `undefined` values before generating, so an undefined or omitted param for a dynamic segment lands here. Spread (`...rest`) params are optional and default to empty string.

Solutions

  1. Supply a concrete string for every dynamic segment named in the file (`[lang]/[slug]` needs both `lang` and `slug`)
  2. Check for typos between the bracket name in the filename and the keys in `params`
  3. Default or filter undefined values before returning: `params: { slug: post.slug ?? post.id }`
  4. Remember spread params (`[...rest]`) are the only optional ones

Example fix

// before — src/pages/blog/[lang]/[slug].astro
export async function getStaticPaths() {
  return [{ params: { lang: 'en' } }]; // slug missing → TypeError
}

// after
return [{ params: { lang: 'en', slug: 'hello' } }];
Defensive patterns

Strategy: type-guard

Validate before calling

// Assert completeness before returning getStaticPaths entries
const required = ['lang', 'slug']; // names inside the file's brackets
const complete = paths.every((p) => hasAllParams(required, p.params));
if (!complete) throw new Error('getStaticPaths entry missing a dynamic param');

Type guard

// Every dynamic (non-spread) param must be a defined string
export function hasAllParams(required: string[], params: Record<string, unknown>): boolean {
  return required.every((k) => typeof params[k] === 'string');
}

Prevention

When it happens

Trigger: `getStaticPaths()` for `src/pages/blog/[lang]/[slug].astro` returning `[{ params: { lang: 'en' } }]` (slug missing); a typo'd key (`{ slugs: 'x' }` vs the file's `[slug]`); values that are `undefined` after filtering, e.g. `{ slug: post.slug }` where `post.slug` is undefined; consuming `generatePattern`-style utilities (e.g. sitemap or route-stringify helpers) with incomplete params.

Common situations: Optional CMS fields that sometimes yield undefined slugs; refactoring filenames without updating params keys; building path strings from partial objects in integrations.

Related errors


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

Appendix: source

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

function sanitizeParams(params: Record<string, string | number>): Record<string, string | number> {
	return Object.fromEntries(
		Object.entries(params).map(([key, value]) => {
			if (typeof value === 'string') {
				return [key, value.normalize().replace(/#/g, '%23').replace(/\?/g, '%3F')];
			}
			return [key, value];
		}),
	);
}

function getParameter(part: RoutePart, params: Record<string, string | number>): string | number {
	if (part.spread) {
		return params[part.content.slice(3)] ?? '';
	}

	if (part.dynamic) {
		if (params[part.content] === undefined) {
			throw new TypeError(`Missing parameter: ${part.content}`);
		}

		return params[part.content];
	}

	return part.content
		.normalize()
		.replace(/\?/g, '%3F')
		.replace(/#/g, '%23')
		.replace(/%5B/g, '[')
		.replace(/%5D/g, ']');
}

function getSegment(segment: RoutePart[], params: Record<string, string | number>): string {
	const segmentPath = segment.map((part) => getParameter(part, params)).join('');

	return segmentPath ? collapseDuplicateLeadingSlashes('/' + segmentPath) : '';
}

View on GitHub (pinned to 52e6c34790)