{"record":{"id":"5c4085488645bded","repo":"withastro/astro","slug":"astro-locals-runtime-env-has-been-removed-in-astro","errorCode":null,"errorMessage":"Astro.locals.runtime.env has been removed in Astro v6. Use 'import { env } from \"cloudflare:workers\"' instead.","messagePattern":"Astro\\.locals\\.runtime\\.env has been removed in Astro v6\\. Use 'import (.+?) from \"cloudflare:workers\"' instead\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/integrations/cloudflare/src/utils/cf-helpers.ts","lineNumber":72,"sourceCode":"export function createErrorPageFetch(env: Env): (url: string) => Promise<Response> {\n\treturn async (url: string) => {\n\t\treturn env.ASSETS.fetch(url.replace(/\\.html$/, '')) as unknown as Response;\n\t};\n}\n\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},","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/integrations/cloudflare/src/utils/cf-helpers.ts#L54-L90","documentation":"Thrown by `@astrojs/cloudflare` (v6+) when user code accesses `Astro.locals.runtime.env`. In Astro v6 the `runtime` shim on `locals` is a non-enumerable property whose `env` getter always throws, directing users to import `env` from `cloudflare:workers` instead. This is a hard migration break: the old `runtime.env` object that exposed Cloudflare bindings has been removed.","triggerScenarios":"Calling `Astro.locals.runtime.env.MY_BINDING` in a page, endpoint, or middleware running under the Cloudflare adapter on Astro v6. The getter is defined on `locals.runtime` and throws on any property access pattern that touches `env`.","commonSituations":"Upgrading an Astro v5 (or earlier) Cloudflare project to v6 without migrating binding access. Copy-pasting v5 tutorial code. The `runtime` property is non-enumerable, so it is invisible in `console.log`/`Object.keys`, making the migration trap easy to miss during debugging.","solutions":["Replace `Astro.locals.runtime.env.MY_BINDING` with `import { env } from 'cloudflare:workers'; env.MY_BINDING`.","Use a codemod or project-wide search for `locals.runtime.env` and `runtime.env` to find all call sites.","Update TypeScript types if your project extended the old `runtime.env` typing."],"exampleFix":"// before\nexport const GET = ({ locals }) => Response.json(locals.runtime.env.MY_KV);\n\n// after\nimport { env } from 'cloudflare:workers';\nexport const GET = () => Response.json(env.MY_KV);","handlingStrategy":"validation","validationCode":"// Codemod guard: fail the build if any v5 runtime.env usage remains.\n// In a prebuild script:\nconst { execSync } = require('child_process');\nconst out = execSync('grep -rn \"runtime.env\" src/ || true').toString();\nif (out) { console.error('Migrate runtime.env to cloudflare:workers env'); process.exit(1); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Search for `locals.runtime.env` and `runtime.env` before upgrading to Astro v6.","Use `import { env } from 'cloudflare:workers'` as the single source of bindings.","Note `locals.runtime` is non-enumerable — do not rely on it appearing in logs."],"tags":["cloudflare","astro-v6","migration","breaking-change","bindings"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}