sveltejs/kit · error · Error

Invalid redirect location ${JSON.stringify(location)}: this

Error message

Invalid redirect location ${JSON.stringify(location)}: this string contains characters that cannot be used in HTTP headers

What it means

The `Redirect` class validates that the `location` string can be safely placed in a `Location` HTTP header. If `new Headers({ location })` throws — e.g. the string contains newlines, control characters, or other invalid header characters — the redirect is rejected rather than risking header injection or malformed responses.

Source

Thrown at packages/kit/src/exports/internal/shared.js:35

/**
 * An `HttpError` whose body is already in its final, user-facing form — either produced by the
 * `handleError` hook on the server and reconstructed here from the response, or authored directly
 * by the client runtime. Unlike a plain `HttpError` (which represents a fresh `error(...)` call
 * that the hook has yet to see), `handleError` must not run on it.
 * @extends HttpError
 */
export class HandledHttpError extends HttpError {}

export class Redirect {
	/**
	 * @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status
	 * @param {string} location
	 */
	constructor(status, location) {
		try {
			new Headers({ location });
		} catch {
			throw new Error(
				`Invalid redirect location ${JSON.stringify(location)}: ` +
					'this string contains characters that cannot be used in HTTP headers'
			);
		}

		this.status = status;
		this.location = location;
	}
}

/**
 * An error that was thrown from within the SvelteKit runtime that is not fatal and doesn't result in a 500, such as a 404.
 * `SvelteKitError` goes through `handleError`.
 * @extends Error
 */
export class SvelteKitError extends Error {
	/**
	 * @param {number} status

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Sanitize the location before redirecting: trim whitespace and strip or reject control characters (`/[\u0000-\u001F\u007F]/`).
  2. Validate the target against an allowlist of paths or origins before calling `redirect`.
  3. Use `encodeURI`/`encodeURIComponent` for user-derived path segments.
  4. If the input is untrusted and validation fails, redirect to a safe default (e.g. `/`) instead.

Example fix

// before
redirect(302, formData.get('next'));
// after
const next = String(formData.get('next') ?? '/');
if (!/^[\u0021-\u007E]+$/.test(next) || !next.startsWith('/')) redirect(302, '/');
else redirect(302, next);
Defensive patterns

Strategy: validation

Validate before calling

function safeLocation(loc) {
  const s = String(loc).trim();
  return /[\u0000-\u001F\u007F]/.test(s) ? null : s;
}
const loc = safeLocation(input);
if (!loc) redirect(302, '/');

Type guard

const isHeaderSafe = (s) => typeof s === 'string' && s.length > 0 && !/[\u0000-\u001F\u007F]/.test(s);

Try / catch

try {
  new Headers({ location: target });
  redirect(302, target);
} catch {
  redirect(302, '/'); // safe fallback
}

Prevention

When it happens

Trigger: Calling `redirect(302, userInput)` where the input contains `\n`, `\r`, or other non-printable/control characters; building a location from decoded data with embedded newlines.

Common situations: Redirecting to a URL taken verbatim from a query parameter or form field that contains encoded line breaks; log-parsing or copy-paste artifacts introducing newlines into the target URL (a classic open-redirect/header-injection vector).

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/f80f73d9ef068df3. Report an issue: GitHub.