withastro/astro · error · Error
Astro.locals.runtime.ctx has been removed in Astro v6. Use '
Error message
Astro.locals.runtime.ctx has been removed in Astro v6. Use 'Astro.locals.cfContext' instead.
What it means
Astro v6 removed the `Astro.locals.runtime.ctx` accessor from the Cloudflare adapter. The `runtime` object is now a non-enumerable property whose getters all throw to force migration. `ctx` (the Cloudflare ExecutionContext used for `waitUntil`, `passThroughOnException`, etc.) was moved to `Astro.locals.cfContext`. The throw is intentional and fires the moment user code reads the property.
Source
Thrown at packages/integrations/cloudflare/src/utils/cf-helpers.ts:87
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;
}
/**
* Extracts the client IP address from the `cf-connecting-ip` header.
*/
export function getClientAddress(request: Request): string | undefined {
return getValidatedIpFromHeader(request.headers.get('cf-connecting-ip'));
}
View on GitHub (pinned to d081033d5f)
Solutions
- Replace every `Astro.locals.runtime.ctx` with `Astro.locals.cfContext` — the object shape (ExecutionContext) is identical.
- If you only need `waitUntil`, use `Astro.locals.cfContext.waitUntil(...)`.
- Grep the codebase for `locals.runtime` and migrate `env`, `cf`, `caches`, and `ctx` to their v6 replacements (`import { env } from 'cloudflare:workers'`, `Astro.request.cf`, the global `caches`, and `Astro.locals.cfContext`).
- If a third-party integration reads `runtime.ctx`, upgrade it or wrap it so it consumes `cfContext`.
Example fix
// before Astro.locals.runtime.ctx.waitUntil(promise); const cfCtx = Astro.locals.runtime.ctx; // after Astro.locals.cfContext.waitUntil(promise); const cfCtx = Astro.locals.cfContext;
Defensive patterns
Strategy: validation
Validate before calling
const hasCfContext = !!(Astro.locals as any).cfContext;
if (!hasCfContext) throw new Error('Cloudflare cfContext missing — wrong adapter?');
const ctx = (Astro.locals as any).cfContext; Type guard
function hasCfContext(locals: Record<string, unknown>): locals is { cfContext: ExecutionContext } {
return typeof (locals as any).cfContext === 'object' && (locals as any).cfContext !== null;
} Try / catch
// Avoid catching — migrate the accessor. Catching hides the migration need.
// If you must guard third-party code:
function safeCtx(locals: any) {
try { return locals.cfContext; } catch { return undefined; }
} Prevention
- Codemod `Astro.locals.runtime.{ctx,env,cf,caches}` to their v6 replacements before upgrading.
- Search the repo for `locals.runtime` as part of the v6 upgrade checklist.
- Upgrade `@astrojs/cloudflare` in lockstep with `astro` v6.
When it happens
Trigger: User page/middleware/API code on a Cloudflare adapter deployment accesses `Astro.locals.runtime.ctx` (e.g. `Astro.locals.runtime.ctx.waitUntil(p)`). The getter is defined with `get ctx(): never`, so any read — even `typeof` checks, destructuring, or serialization — synchronously throws.
Common situations: Upgrading `@astrojs/cloudflare` to a v6-compatible release while keeping pre-v6 middleware or endpoints that referenced `runtime.ctx`. Copying older Cloudflare adapter snippets from docs or blogs. SSR code that stored `const { ctx } = Astro.locals.runtime` at module/request scope.
Related errors
- Failed to prerender ${request.url}: ${prerenderError}
- Please use Astro.url instead.
- ActionCalledFromServerError
- Configured image service is not a local service
- FontFileUrlNotFound
AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12).
Data as JSON: /api/errors/94eee2c8c2c52a18.
Report an issue: GitHub.