Edge-Instrumentation bundle pulls email.ts's node:crypto — operator alert leg cannot run on an edge-runtime 500
Turbopack emits 3 warnings on every build: 'A Node.js module is loaded (crypto) which is not supported in the Edge Runtime', import trace #1 [Edge Instrumentation] -> src/lib/email.ts -> src/instrumentation.ts. Sites: src/lib/email.ts:135 and :176, both already dynamic-imported with a comment saying crypto must not be statically bundled — the dynamic import avoids the static bundle but does NOT keep the module out of the edge instrumentation trace. Why it matters: onRequestError is the operator-alert path (PLUTO-166). src/proxy.ts is a middleware, so Next builds an EDGE variant of instrumentation. A 500 raised in the edge runtime would run onRequestError there, hit the crypto import inside sendServerErrorNotification's dedupe-key computation, throw, and be swallowed by the existing 'never rethrow' guard -> console.error only, no alert email. The durable appEvents row is a separate guarded leg and is unaffected. NOT MEASURED, and this is the part to establish first: whether any 500 actually reaches the edge instrumentation variant in production, or whether every served route is nodejs. The warning proves the bundle exists, not that the path executes. Do not fix before measuring — an unexercised path is not an outage. Pre-existing, not introduced by the orphan-slice commits (present identically on 87523d0/ad6db96/f08751e/216d403 builds). Found during slice C/D PTD log review 2026-08-07. Options if the path is live: runtime-agnostic hash (Web Crypto subtle.digest, available in both), or split the alert sender so the edge variant uses a crypto-free key.
Questions
Activity
-
Correction from the filer: priority reads 2 but that value landed on TYPE, not priority — 'wi add' positional order is [type] [priority] and I passed one number. Priority is at its default. Intended priority for this item is 2 (normal), which is what the default happens to be, so the effective value is correct by accident; the type field is meaningless. Same mistake as PLUTO-686, which is genuinely mis-prioritised by it.
-
MEASUREMENT (the step this WI said to do first) — coder-pluto-cc, 2026-08-07, Vercel get_runtime_errors, project prj_0t8ww1, 7d window. RESULT: no 500 reaches the edge instrumentation variant. 11 error groups; every onRequestError occurrence carries routeType 'render' or 'action', never 'middleware'. Every stack frame is Node-runtime: /var/task/..., node:internal/process/task_queues, pg-pool. Zero edge frames anywhere in the window. Corroborating source read: NO route in src/ declares runtime='edge' (grep, whole tree). 11 routes declare runtime='nodejs' explicitly; the rest inherit the nodejs default. src/proxy.ts (middleware) is the ONLY edge surface in the app, which is why Next builds the edge instrumentation variant at all. So the Turbopack warning is real about the BUNDLE and inert about the PATH: the edge variant is emitted because a middleware exists, and nothing routes a 500 into it. COVERAGE BOUND — what this does NOT establish. Vercel caps the lookback at 7d, so this is a 7-day observation, not a lifetime one. Worse for inference: the window's errors are dominated by a single 2026-07-31 schema incident (relation comisionAdjuntos does not exist, 28+10+6+5+5+2 occurrences, all inside one 56-minute span). Outside that incident the app produced almost no 500s, so the sample is thin and NOT a demonstration that middleware cannot throw — only that it did not, here. An unexercised path stayed unexercised. RECOMMENDATION: do not fix. Downgrade to a documentation note in src/lib/email.ts explaining that the crypto import shows in the edge trace but no 500 reaches it, so the next reader does not re-raise the warning as a defect. Re-measure if a route ever opts into runtime='edge' — that is the event that would make this live, and it is the trigger to watch for rather than a date.
-
Measured: no 500 reaches the edge instrumentation variant in the 7d Vercel window (dominated by the 2026-07-31 incident) — no runtime='edge' route besides proxy.ts, zero middleware onRequestError hits. Coverage is 'did not' not 'cannot'. Closing without a code fix per coder-pluto-cc's recommendation; a comment in email.ts documents the bundle-vs-path distinction so it isn't re-raised.