withastro/astro · error · Error

Astro.locals.runtime.cf has been removed in Astro v6. Use…

Error message

Astro.locals.runtime.cf has been removed in Astro v6. Use 'Astro.request.cf' instead.

What it means

Part of the same Astro v6 removal: `Astro.locals.runtime.cf` no longer exists, and the adapter's trap getter throws this message pointing at the replacement. `cf` (request metadata like country, ASN, TLS info) must now be read from `Astro.request.cf`, which Cloudflare populates per request.

Solutions

  1. Replace `Astro.locals.runtime.cf` with `Astro.request.cf` everywhere.
  2. Grep for `locals.runtime` to catch the sibling removals (env, caches, ctx) in the same pass.
  3. Follow the Astro v6 upgrade notes for the Cloudflare adapter.
  4. Stay on Astro v5 + matching adapter if you cannot migrate yet.

Example fix

// before
const country = Astro.locals.runtime.cf.country;

// after
const country = Astro.request.cf?.country;
Defensive patterns

Strategy: type-guard

Type guard

type LegacyCf = Record<string, unknown> | undefined;
function safeCf(locals: App.Locals, request: Request): LegacyCf {
  // Preferred v6 source first
  if ('cf' in request && request.cf) return request.cf as LegacyCf;
  const runtime = (locals as Record<string, unknown>).runtime;
  if (!runtime || typeof runtime !== 'object') return undefined;
  try {
    return (runtime as { cf: unknown }).cf as LegacyCf;
  } catch {
    return undefined; // v6 trap — migrate callers to Astro.request.cf
  }
}

Prevention

When it happens

Trigger: In an Astro v6 + @astrojs/cloudflare project, any code accessing `Astro.locals.runtime.cf` (geo checks, bot scoring, locale negotiation) throws as soon as the getter runs.

Common situations: Post-upgrade v5 projects with geo/IP-based routing or analytics code; tutorials written against the old `locals.runtime` API.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/378d336953a14f6b. Report an issue: GitHub.

Appendix: source

Thrown at packages/integrations/cloudflare/src/utils/cf-helpers.ts:77

/**
 * Creates the Cloudflare-specific locals object with `cfContext`
 * and deprecated `runtime` property getters.
 */
export function createLocals(ctx: ExecutionContext): Runtime {
	const locals: Runtime = {
		cfContext: ctx,
	};
	Object.defineProperty(locals, 'runtime', {
		enumerable: false,
		value: {
			get env(): never {
				throw new Error(
					`Astro.locals.runtime.env has been removed in Astro v6. Use 'import { env } from "cloudflare:workers"' instead.`,
				);
			},
			get cf(): never {
				throw new Error(
					`Astro.locals.runtime.cf has been removed in Astro v6. Use 'Astro.request.cf' instead.`,
				);
			},
			get caches(): never {
				throw new Error(
					`Astro.locals.runtime.caches has been removed in Astro v6. Use the global 'caches' object instead.`,
				);
			},
			get ctx(): never {
				throw new Error(
					`Astro.locals.runtime.ctx has been removed in Astro v6. Use 'Astro.locals.cfContext' instead.`,
				);
			},
		},
	});
	return locals;
}

View on GitHub (pinned to 52e6c34790)