{"record":{"id":"378d336953a14f6b","repo":"withastro/astro","slug":"astro-locals-runtime-cf-has-been-removed-in-astro","errorCode":null,"errorMessage":"Astro.locals.runtime.cf has been removed in Astro v6. Use 'Astro.request.cf' instead.","messagePattern":"Astro\\.locals\\.runtime\\.cf has been removed in Astro v6\\. Use 'Astro\\.request\\.cf' instead\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/integrations/cloudflare/src/utils/cf-helpers.ts","lineNumber":77,"sourceCode":"\n/**\n * Creates the Cloudflare-specific locals object with `cfContext`\n * and deprecated `runtime` property getters.\n */\nexport function createLocals(ctx: ExecutionContext): Runtime {\n\tconst locals: Runtime = {\n\t\tcfContext: ctx,\n\t};\n\tObject.defineProperty(locals, 'runtime', {\n\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","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/integrations/cloudflare/src/utils/cf-helpers.ts#L59-L95","documentation":"Thrown by `@astrojs/cloudflare` (v6+) when user code accesses `Astro.locals.runtime.cf`. The old `runtime.cf` object exposing Cloudflare request properties has been removed; the non-enumerable `runtime` shim's `cf` getter always throws, directing users to `Astro.request.cf` instead.","triggerScenarios":"Calling `Astro.locals.runtime.cf.country`, `.city`, `.timezone`, etc. in code running under the Cloudflare adapter on Astro v6. Any read of the `cf` property on `locals.runtime` triggers the getter throw.","commonSituations":"Upgrading a v5 Cloudflare project to v6 that read Geo/IP info from `runtime.cf`. Copy-pasting v5 geo-location tutorial code. The non-enumerable nature of `runtime` hides the property in introspection, obscuring the source.","solutions":["Replace `Astro.locals.runtime.cf` with `Astro.request.cf`.","Search the codebase for `runtime.cf` and `.cf.` patterns to catch all usages.","Note `Astro.request.cf` is per-request (already populated by Cloudflare), so no extra fetch is needed."],"exampleFix":"// before\nexport const GET = ({ locals }) => json({ country: locals.runtime.cf.country });\n\n// after\nexport const GET = ({ request }) => json({ country: request.cf?.country });","handlingStrategy":"validation","validationCode":"// Prebuild check for runtime.cf usage.\nconst { execSync } = require('child_process');\nconst out = execSync('grep -rn \"runtime\\\\.cf\" src/ || true').toString();\nif (out) { console.error('Migrate runtime.cf to Astro.request.cf'); process.exit(1); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Migrate all `locals.runtime.cf` to `Astro.request.cf` during the v6 upgrade.","Treat request geo data as per-request: read from Astro.request, not locals.","Remember `locals.runtime` is non-enumerable and invisible to console.log."],"tags":["cloudflare","astro-v6","migration","breaking-change","request-properties"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}