sveltejs/kit · error · Error
Cannot redirect to external URL ${JSON.stringify(location)}.
Error message
Cannot redirect to external URL ${JSON.stringify(location)}. To redirect to an external URL, pass `{ external: true }` or an allowlist of permitted origins as the third argument to `redirect` (prod: 'Cannot redirect to external URL unless explicitly allowed') What it means
`redirect()` refuses external (absolute cross-origin) URLs by default. To redirect off-site you must explicitly opt in with `{ external: true }` or pass an allowlist of permitted origins as the third argument, protecting against open-redirect vulnerabilities. In production the message is intentionally vague to avoid leaking validation details.
Source
Thrown at packages/kit/src/exports/url.js:48
function is_javascript_location(location) {
try {
return javascript_protocols.has(new URL(location, REDIRECT_BASE).protocol);
} catch {
return false;
}
}
/**
* @param {string} location
* @param {{ external?: boolean | string[] }} [options]
*/
export function validate_redirect_location(location, options) {
if (!is_external_location(location)) return;
const external = options?.external;
if (!external) {
throw new Error(
DEV
? `Cannot redirect to external URL ${JSON.stringify(location)}. ` +
'To redirect to an external URL, pass `{ external: true }` or an allowlist of permitted origins as the third argument to `redirect`'
: 'Cannot redirect to external URL unless explicitly allowed'
);
}
if (external === true) {
if (is_javascript_location(location)) {
throw new Error(
DEV
? `Cannot redirect to ${JSON.stringify(location)} with \`{ external: true }\`. ` +
'The `javascript:` and `data:` protocols must be explicitly listed in the `external` allowlist'
: 'Cannot redirect to external URL unless explicitly allowed'
);
}
return;View on GitHub (pinned to 03f1687fe6)
Solutions
- If the target is truly external, call `redirect(status, location, { external: true })`.
- Better: pass an allowlist of permitted origins as the third argument, e.g. `redirect(302, url, { external: ['https://partner.com'] })`.
- If the target should be internal, strip the origin: use `new URL(location).pathname + new URL(location).search` before redirecting.
- Never derive the redirect target directly from untrusted input without allowlisting.
Example fix
// before
redirect(302, event.url.searchParams.get('next'));
// after
const next = event.url.searchParams.get('next') ?? '/';
redirect(302, next, { external: ['https://trusted.example.com'] }); Defensive patterns
Strategy: validation
Validate before calling
const allowedExternalOrigins = ['https://trusted.example.com'];
function canRedirect(loc, opts) {
const u = new URL(loc, 'http://internal');
const isExternal = u.origin !== 'http://internal';
if (!isExternal) return true;
return Array.isArray(opts?.external)
? opts.external.includes(u.origin)
: opts?.external === true;
}
if (!canRedirect(target, opts)) target = '/'; Type guard
const isExternalUrl = (s) => {
try { return new URL(s, 'http://internal').origin !== 'http://internal'; } catch { return false; }
}; Try / catch
try {
redirect(302, target);
} catch (e) {
if (String(e.message).includes('external URL')) {
redirect(302, '/'); // or re-redirect with allowlist
} else throw e;
} Prevention
- Normalize internal targets to pathname+search before redirecting.
- Maintain an explicit origin allowlist for genuine external redirects.
- Never pass untrusted ?next= parameters through as absolute URLs.
- Consider Redirect(302, '/') as a fallback for blocked targets.
When it happens
Trigger: Calling `redirect(302, 'https://other-site.com/path')` without options; redirecting to an absolute URL built from query params like `?next=https://evil.com` without `{ external: true }` or an origins allowlist.
Common situations: Post-login `?redirectTo=` flows pointing at absolute URLs; integrating OAuth return URLs; environment-based redirects where a base URL is absolute (e.g. `https://app.example.com/dashboard`) even in same-origin deployments.
Related errors
- Cannot redirect to ${JSON.stringify(location)} with `{ exter
- Invalid status code
- Invalid redirect location ${JSON.stringify(location)}: this
- Cannot redirect to ${JSON.stringify(location)}: URL origin i
- ${keypath} cannot be empty
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/542c8015a439ba52.
Report an issue: GitHub.