withastro/astro · error · AstroError

RedirectWithNoLocation

RedirectWithNoLocation

Error message

A redirect must be given a location with the `Location` header.

What it means

Thrown by getRedirectLocationOrThrow() when a Response with a 3xx redirect status lacks a 'location' header. Astro requires every redirect Response to carry a Location header so the browser knows where to navigate. Without it the redirect is meaningless and the runtime refuses to serve it.

Source

Thrown at packages/astro/src/core/redirects/validate.ts:7

import { AstroError, AstroErrorData } from '../errors/index.js';

export function getRedirectLocationOrThrow(headers: Headers): string {
	let location = headers.get('location');

	if (!location) {
		throw new AstroError({
			...AstroErrorData.RedirectWithNoLocation,
		});
	}

	return location;
}

View on GitHub (pinned to d081033d5f)

Solutions

  1. Use Astro.redirect('/path') which sets the Location header automatically.
  2. If building the Response manually, always pass headers: { Location: '/target' }.
  3. Inspect middleware/onRequest handlers that touch Astro.response or the returned Response to ensure they preserve Location.
  4. Log response.headers.get('location') right before returning to confirm the header is present.

Example fix

// before
return new Response(null, { status: 302 });

// after
return new Response(null, { status: 302, headers: { Location: '/login' } });
// or simply
return Astro.redirect('/login');
Defensive patterns

Strategy: validation

Validate before calling

function hasRedirectLocation(response: Response): boolean {
  return Boolean(response.headers.get('location'));
}
// before returning a redirect:
const res = new Response(null, { status: 302, headers: { Location: '/x' } });
if (!hasRedirectLocation(res)) throw new Error('missing Location');

Type guard

function isRedirectWithLocation(res: Response): res is Response & { headers: Headers } {
  return res.status >= 300 && res.status < 400 && res.headers.has('location');
}

Try / catch

try {
  const loc = getRedirectLocationOrThrow(response.headers);
} catch (e) {
  // ensure Location is set before retrying
  response.headers.set('Location', '/fallback');
}

Prevention

When it happens

Trigger: Returning a Response with status 301/302/307/308 but no 'Location' header; calling Astro.redirect() and then mutating the Response to strip the header; manually constructing new Response(null, { status: 302 }) without headers; an integration or middleware replacing response headers.

Common situations: Manually building a redirect Response in an endpoint or page instead of using Astro.redirect(url); middleware that clones a redirect Response and drops headers; adapter/proxy that strips Location before Astro reads it.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/45a03e27a9ee5589. Report an issue: GitHub.