{"record":{"id":"82c233b5d40e0849","repo":"withastro/astro","slug":"unsupportedexternalredirect","errorCode":"UnsupportedExternalRedirect","errorMessage":"The destination URL in the external redirect from \"${from}\" to \"${to}\" is unsupported.","messagePattern":"The destination URL in the external redirect from \"(.+?)\" to \"(.+?)\" is unsupported\\.","errorType":"validation","errorClass":"AstroError","httpStatus":null,"severity":"error","filePath":"packages/astro/src/core/routing/create-manifest.ts","lineNumber":542,"sourceCode":"\t\tconst pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic)\n\t\t\t? `/${segments.map((segment) => segment[0].content).join('/')}`\n\t\t\t: null;\n\t\tconst params = segments\n\t\t\t.flat()\n\t\t\t.filter((p) => p.dynamic)\n\t\t\t.map((p) => p.content);\n\t\tconst route = joinSegments(segments);\n\n\t\tlet destination: string;\n\t\tif (typeof to === 'string') {\n\t\t\tdestination = to;\n\t\t} else {\n\t\t\tdestination = to.destination;\n\t\t}\n\n\t\t// check if the link starts with http or https; if not, throw an error\n\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,","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/core/routing/create-manifest.ts#L524-L560","documentation":"UnsupportedExternalRedirect: a configured redirect's destination is a parseable URL that does not start with http:// or https://. Astro only permits external redirects over HTTP(S); other protocols (ftp://, mailto:, relative, or malformed scheme) are rejected at manifest build time.","triggerScenarios":"Setting redirects in astro.config to a destination like 'ftp://example.com', '//example.com', or a protocol-relative URL; using a string that URL.canParse accepts but lacks the http(s) scheme.","commonSituations":"Copying a non-http URL into config.redirects; protocol-relative URLs from legacy configs; accidentally prefixing with a wrong scheme; data-driven redirect config populated from a CMS.","solutions":["Change the destination to start with http:// or https://.","If the destination is a local path, drop the scheme and use a root-relative '/path'.","Validate redirect destinations against /^https?:\\/\\// before deploying config."],"exampleFix":"// before — astro.config.mjs\nredirects: { '/old': 'ftp://files.example.com' }\n\n// after\nredirects: { '/old': 'https://files.example.com' }","handlingStrategy":"validation","validationCode":"function isSupportedExternalRedirect(dest: string): boolean {\n  return !URL.canParse(dest) || /^https?:\\/\\//.test(dest);\n}\n// validate redirect destinations in config before build","typeGuard":"function isHttpUrl(value: string): boolean {\n  return /^https?:\\/\\//.test(value);\n}","tryCatchPattern":null,"preventionTips":["Use only http(s):// or root-relative paths in config.redirects.","Lint redirect destinations against /^https?:\\/\\// or a leading '/' in CI.","Avoid protocol-relative '//host' URLs."],"tags":["redirect","config","validation","url"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}