{"record":{"id":"f018f9d0ab18275d","repo":"withastro/astro","slug":"invalidredirectdestination","errorCode":"InvalidRedirectDestination","errorMessage":"The redirect from \"${from}\" to \"${to}\" is invalid. The destination \"${to}\" does not match any existing route in your project.","messagePattern":"The redirect from \"(.+?)\" to \"(.+?)\" is invalid\\. The destination \"(.+?)\" does not match any existing route in your project\\.","errorType":"exception","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/create-manifest.ts","lineNumber":559,"sourceCode":"\t\tif (URL.canParse(destination) && !/^https?:\\/\\//.test(destination)) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...UnsupportedExternalRedirect,\n\t\t\t\tmessage: UnsupportedExternalRedirect.message(from, destination),\n\t\t\t});\n\t\t}\n\n\t\tconst redirectRoute = routeMap.get(destination);\n\n\t\t// If the source has dynamic params and the redirect will be prerendered,\n\t\t// we need a valid redirectRoute to map them. Without it, the build will fail\n\t\t// later with a misleading error. Catch this early and provide a clear error message.\n\t\tif (\n\t\t\tparams.length > 0 &&\n\t\t\t!redirectRoute &&\n\t\t\t!URL.canParse(destination) &&\n\t\t\tgetPrerenderDefault(config)\n\t\t) {\n\t\t\tthrow new AstroError({\n\t\t\t\t...InvalidRedirectDestination,\n\t\t\t\tmessage: InvalidRedirectDestination.message(from, destination),\n\t\t\t});\n\t\t}\n\n\t\t// If the source has dynamic params and the destination route exists but has\n\t\t// fewer params, the build will fail later with a misleading error (e.g.,\n\t\t// \"getStaticPaths required\" pointing at the wrong file). Catch this early.\n\t\tif (\n\t\t\tparams.length > 0 &&\n\t\t\tredirectRoute &&\n\t\t\t!URL.canParse(destination) &&\n\t\t\tgetPrerenderDefault(config)\n\t\t) {\n\t\t\tconst destParams = redirectRoute.params ?? [];\n\t\t\tconst missingParams = params.filter((p) => !destParams.includes(p));\n\t\t\tif (missingParams.length > 0) {\n\t\t\t\tthrow new AstroError({","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/withastro/astro/blob/e294953aa8aadd98d5be92e60a03037b05dbdfd4/packages/astro/src/core/routing/create-manifest.ts#L541-L577","documentation":"When a `redirects` source contains dynamic params (e.g. `/old/[slug]`), the static build must substitute those params into the destination to emit one redirect file per value — which requires the destination to resolve to a real route. If the destination is not a URL, matches nothing in the route map, and the config prerenders by default, Astro throws `InvalidRedirectDestination` at manifest creation instead of failing later with a misleading error.","triggerScenarios":"`redirects: { '/old/[slug]': '/new-posts' }` where no `/new-posts` route exists (typo or never created); renaming destination routes without updating the redirects map; destinations with leading-path typos like `/post/[slug]` vs `/posts/[slug]`.","commonSituations":"Maintaining a legacy redirect table as the site evolves; content migrations that move routes after redirects were written; large configs where a stale entry goes unnoticed until build.","solutions":["Fix the destination to an existing route (check `src/pages` for the exact pattern)","Carry the dynamic segment over: `'/old/[slug]': '/posts/[slug]'`","Use a full `https://…` URL for external targets (URLs skip route matching)","Add a CI check that every non-URL redirect destination matches a page in `src/pages`"],"exampleFix":"// before\nredirects: { '/old/[slug]': '/new-posts' }  // no /new-posts route exists\n\n// after\nredirects: { '/old/[slug]': '/posts/[slug]' }  // existing dynamic route","handlingStrategy":"validation","validationCode":"// Pre-build check: every non-URL redirect destination must match a pages route\nimport { getRoutes } from './route-helpers.js'; // builds expected paths from src/pages\nconst known = await getRoutes(); // e.g. Set like '/posts/[slug]', '/about'\nfor (const [from, to] of Object.entries(redirects)) {\n  const dest = typeof to === 'string' ? to : to.destination;\n  if (URL.canParse(dest)) continue; // external, fine\n  if (from.includes('[') && ![...known].some((r) => routeMatches(r, dest))) {\n    throw new Error(`redirect ${from} → ${dest}: destination route not found`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["After renaming/removing routes, grep the redirects map for the old paths","Prefer destinations that carry the same dynamic segments as the source","Add a config-validation script to CI that cross-checks redirects against src/pages"],"tags":["redirects","config","dynamic-routes","build"],"backgroundTag":"redirect-destination-not-found","analyzedSha":"e294953aa8aadd98d5be92e60a03037b05dbdfd4","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}