Problem
/api/ask returns a 500 on every request when the host site uses
@astrojs/cloudflare 14 with Astro 7. Not just the agentic path — keyword
search dies with it, because both go through the same endpoint. The Cloudflare
adapter is the one we point people at in the quick start, so on current Astro
the flagship path is broken end to end.
Astro.locals.runtime.env has been removed in Astro v6.
Use 'import { env } from "cloudflare:workers"' instead.
at Object.get env [as env] (@astrojs/cloudflare/dist/utils/cf-helpers.js:31:15)
at resolveEnv (@hevmind/ask/src/endpoint.ts:33)
Cause
endpoint.ts:33:
const fromRuntime = (locals as { runtime?: { env?: Record<string, string> } })?.runtime?.env ?? {};
The adapter replaced runtime.env with a getter that throws. Optional
chaining and ?? {} only defend against null/undefined, so neither helps —
the throw happens during property access, before any fallback is reached. The
defensive-looking code reads as safe and isn't.
Worth noting the failure is total rather than partial: because resolveEnv runs
on the way to any response, a site with no API key configured at all — which
should degrade to keyword-only per the README's "Server Requirements" — still
500s.
Reproduce
Astro 7 + Starlight, @astrojs/cloudflare 14, @hevmind/ask 0.3.4:
curl -X POST localhost:4321/api/ask -H 'content-type: application/json' -d '{"query":"anything"}'
Note you only reach this after working around #2 — the node:fs
import fails to resolve first, so the two bugs surface sequentially.
Fix
Read the runtime env behind a try/catch, or move to
import { env } from 'cloudflare:workers' as the error suggests. try/catch is
probably the better shape here since resolveEnv deliberately spans Node,
Cloudflare, and build-time sources and shouldn't hard-depend on a
cloudflare: module specifier that only resolves on workerd.
Same pattern appears at
endpoint.ts:52-53
for runtime.ctx (the waitUntil plumbing). I did not confirm whether that
getter throws too, but it should be audited in the same pass — if it does, the
telemetry path has the same total-failure mode.
Coverage gap
Nothing in CI runs the endpoint against workerd, which is why a
release-blocking break on the documented-primary adapter shipped. pnpm test +
typecheck + build all pass. A smoke test that boots the endpoint under
wrangler dev (or vitest with the workers pool) and asserts a keyword query
returns 200 would have caught both this and the node:fs issue.
Found while wiring 0.3.4 into a Starlight docs site. Present on main
(a3204b4), not just the 0.3.4 tag. I worked around it by switching that site to
@astrojs/node, which has neither problem.
Problem
/api/askreturns a 500 on every request when the host site uses@astrojs/cloudflare14 with Astro 7. Not just the agentic path — keywordsearch dies with it, because both go through the same endpoint. The Cloudflare
adapter is the one we point people at in the quick start, so on current Astro
the flagship path is broken end to end.
Cause
endpoint.ts:33:The adapter replaced
runtime.envwith a getter that throws. Optionalchaining and
?? {}only defend againstnull/undefined, so neither helps —the throw happens during property access, before any fallback is reached. The
defensive-looking code reads as safe and isn't.
Worth noting the failure is total rather than partial: because
resolveEnvrunson the way to any response, a site with no API key configured at all — which
should degrade to keyword-only per the README's "Server Requirements" — still
500s.
Reproduce
Astro 7 + Starlight,
@astrojs/cloudflare14,@hevmind/ask0.3.4:Note you only reach this after working around #2 — the
node:fsimport fails to resolve first, so the two bugs surface sequentially.
Fix
Read the runtime env behind a
try/catch, or move toimport { env } from 'cloudflare:workers'as the error suggests.try/catchisprobably the better shape here since
resolveEnvdeliberately spans Node,Cloudflare, and build-time sources and shouldn't hard-depend on a
cloudflare:module specifier that only resolves on workerd.Same pattern appears at
endpoint.ts:52-53for
runtime.ctx(thewaitUntilplumbing). I did not confirm whether thatgetter throws too, but it should be audited in the same pass — if it does, the
telemetry path has the same total-failure mode.
Coverage gap
Nothing in CI runs the endpoint against workerd, which is why a
release-blocking break on the documented-primary adapter shipped.
pnpm test+typecheck+buildall pass. A smoke test that boots the endpoint underwrangler dev(orvitestwith the workers pool) and asserts a keyword queryreturns 200 would have caught both this and the
node:fsissue.Found while wiring 0.3.4 into a Starlight docs site. Present on
main(a3204b4), not just the 0.3.4 tag. I worked around it by switching that site to
@astrojs/node, which has neither problem.