Summary
public/Application.cfc::onError() begins with:
application.wheelsdi = new wheels.Injector("wheels.Bindings");
unconditionally (line 345). Every uncaught exception — including routine development-mode 404 error pages (Wheels.RouteNotFound, Wheels.ViewNotFound, Wheels.RecordNotFound) — replaces the live container, discarding every registration made in config/services.cfm plus all cached singletons and request-scoped flags. From that moment, inject()-declared services stop resolving: $resolveInjectedServices() silently skips (containsInstance is false) and controllers crash with Element <SERVICE> is undefined in THIS. until the next reload. The request-lifecycle guide's guarantee that beforeAction filters "can rely on injected services" is broken by the first stray 404.
Repro (adobe2023 harness, develop @ f668c50 — code path is engine-neutral)
A/B in one warm app:
# 1. services.cfm registers probeService; Probe controller does inject("probeService")
# and a private before-filter renders this.probeService.greet()
curl -s 'http://localhost:61753/probe/svc' # -> 200 SVC-OK (containsInstance("probeService") = YES)
# 2. one ordinary dev 404 error page
curl -s -o /dev/null 'http://localhost:61753/zzz/a/b/c' # -> Wheels.RouteNotFound dev error page
# 3. same request as step 1
curl -s 'http://localhost:61753/probe/svc' # -> 500 "Element PROBESERVICE is undefined in THIS."
Diagnostics confirmed application.wheelsdi still exists and the controller's declared injectedServices() still lists probeService — only the container contents were wiped.
Root cause
The re-creation is a fallback for "the Wheels global never came up" (per the surrounding comment), but it runs even when the app is healthy. vendor/wheels/Bindings.cfc:53-56 itself warns that constructing a fresh instance "would clobber application.wheelsdi". Shipped in the 4.0.x line — the line dates to #2623 (2026-05-12), so it is in 4.0.3 GA. Present in public/Application.cfc:345, cli/lucli/templates/app/public/Application.cfc:339, and both examples/*/public/Application.cfc:313.
Proposed direction
Guard the fallback: only construct a new Injector when !StructKeyExists(application, "wheelsdi") (and likewise only rebuild application.wo when missing). Apply to all four same-lineage copies (repo demo app, CLI template, both examples).
Acceptance
Reported by the 2026-06-11 guide behavioral audit (P1 batch 1): request-lifecycle verifier (claim before-filters-after-config-di, code-broken — root cause 1 of 2; root cause 2 is the var di = injector(); Adobe boot crash, filed separately). Findings catalog: docs/superpowers/audits/2026-06-guide-audit-findings.md.
Summary
public/Application.cfc::onError()begins with:application.wheelsdi = new wheels.Injector("wheels.Bindings");unconditionally (line 345). Every uncaught exception — including routine development-mode 404 error pages (
Wheels.RouteNotFound,Wheels.ViewNotFound,Wheels.RecordNotFound) — replaces the live container, discarding every registration made inconfig/services.cfmplus all cached singletons and request-scoped flags. From that moment,inject()-declared services stop resolving:$resolveInjectedServices()silently skips (containsInstanceis false) and controllers crash withElement <SERVICE> is undefined in THIS.until the next reload. The request-lifecycle guide's guarantee that beforeAction filters "can rely on injected services" is broken by the first stray 404.Repro (adobe2023 harness, develop @ f668c50 — code path is engine-neutral)
A/B in one warm app:
Diagnostics confirmed
application.wheelsdistill exists and the controller's declaredinjectedServices()still listsprobeService— only the container contents were wiped.Root cause
The re-creation is a fallback for "the Wheels global never came up" (per the surrounding comment), but it runs even when the app is healthy.
vendor/wheels/Bindings.cfc:53-56itself warns that constructing a fresh instance "would clobber application.wheelsdi". Shipped in the 4.0.x line — the line dates to #2623 (2026-05-12), so it is in 4.0.3 GA. Present inpublic/Application.cfc:345,cli/lucli/templates/app/public/Application.cfc:339, and bothexamples/*/public/Application.cfc:313.Proposed direction
Guard the fallback: only construct a new Injector when
!StructKeyExists(application, "wheelsdi")(and likewise only rebuildapplication.wowhen missing). Apply to all four same-lineage copies (repo demo app, CLI template, both examples).Acceptance
service(),inject(),containsInstance()all intact) — spec or harness check.Reported by the 2026-06-11 guide behavioral audit (P1 batch 1): request-lifecycle verifier (claim
before-filters-after-config-di, code-broken — root cause 1 of 2; root cause 2 is thevar di = injector();Adobe boot crash, filed separately). Findings catalog:docs/superpowers/audits/2026-06-guide-audit-findings.md.