{"record":{"id":"94eee2c8c2c52a18","repo":"withastro/astro","slug":"astro-locals-runtime-ctx-has-been-removed-in-astro","errorCode":null,"errorMessage":"Astro.locals.runtime.ctx has been removed in Astro v6. Use 'Astro.locals.cfContext' instead.","messagePattern":"Astro\\.locals\\.runtime\\.ctx has been removed in Astro v6\\. Use 'Astro\\.locals\\.cfContext' instead\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/integrations/cloudflare/src/utils/cf-helpers.ts","lineNumber":87,"sourceCode":"\t\tenumerable: false,\n\t\tvalue: {\n\t\t\tget env(): never {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Astro.locals.runtime.env has been removed in Astro v6. Use 'import { env } from \"cloudflare:workers\"' instead.`,\n\t\t\t\t);\n\t\t\t},\n\t\t\tget cf(): never {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Astro.locals.runtime.cf has been removed in Astro v6. Use 'Astro.request.cf' instead.`,\n\t\t\t\t);\n\t\t\t},\n\t\t\tget caches(): never {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Astro.locals.runtime.caches has been removed in Astro v6. Use the global 'caches' object instead.`,\n\t\t\t\t);\n\t\t\t},\n\t\t\tget ctx(): never {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Astro.locals.runtime.ctx has been removed in Astro v6. Use 'Astro.locals.cfContext' instead.`,\n\t\t\t\t);\n\t\t\t},\n\t\t},\n\t});\n\treturn locals;\n}\n\n/**\n * Extracts the client IP address from the `cf-connecting-ip` header.\n */\nexport function getClientAddress(request: Request): string | undefined {\n\treturn getValidatedIpFromHeader(request.headers.get('cf-connecting-ip'));\n}\n","sourceCodeStart":69,"sourceCodeEnd":102,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/integrations/cloudflare/src/utils/cf-helpers.ts#L69-L102","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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`."],"exampleFix":"// before\nAstro.locals.runtime.ctx.waitUntil(promise);\nconst cfCtx = Astro.locals.runtime.ctx;\n\n// after\nAstro.locals.cfContext.waitUntil(promise);\nconst cfCtx = Astro.locals.cfContext;","handlingStrategy":"validation","validationCode":"const hasCfContext = !!(Astro.locals as any).cfContext;\nif (!hasCfContext) throw new Error('Cloudflare cfContext missing — wrong adapter?');\nconst ctx = (Astro.locals as any).cfContext;","typeGuard":"function hasCfContext(locals: Record<string, unknown>): locals is { cfContext: ExecutionContext } {\n  return typeof (locals as any).cfContext === 'object' && (locals as any).cfContext !== null;\n}","tryCatchPattern":"// Avoid catching — migrate the accessor. Catching hides the migration need.\n// If you must guard third-party code:\nfunction safeCtx(locals: any) {\n  try { return locals.cfContext; } catch { return undefined; }\n}","preventionTips":["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."],"tags":["cloudflare","astro-v6-migration","deprecation","ssr"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}