You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
URL env switch to production/maintenance 500s and silently reverts — bare $location() undefined at onapplicationstart.cfc:488 when redirectAfterReload auto-enables #3054
?reload=production&password=<secret> — the exact flow documented in the security-hardening guide — never completes. The gate and switch code engage correctly, but the new application's cold start throws, returns a 500, and the next request reverts to the file-configured environment.
Follow the redirect once: → HTTP 500 with the production "Something went wrong" page.
wheels_security.log shows the switch DID engage: Environment switched to 'production' via URL from <ip> + Reload accepted from <ip> (environment: production).
wheels-errors.log shows: No matching function [$LOCATION] found (reproduced twice, timestamps matching the switch attempts).
Next request: app cold-starts again back in development (/wheels/info?format=json → 200; no HSTS from SecurityHeaders). The switch never survives.
Control:?reload=testing&password=smokepw switches cleanly end-to-end (302 → app serves in testing, /wheels/info 404s). This isolates the root cause to production/maintenance targets.
Root cause
vendor/wheels/events/init/orm.cfm auto-flips redirectAfterReload = true when the environment is production or maintenance (if (ListFindNoCase("production,maintenance", application.$wheels.environment)) { application.$wheels.redirectAfterReload = true; }).
With redirectAfterReload=true and url.reload present (always true on the env-switch cold start, because $buildRedirectUrl deliberately preserves reload+password for switches), vendor/wheels/events/onapplicationstart.cfc line 488 runs:
$location(url = local.url, addToken = false);
onapplicationstart.cfc is component { with no extends and no mixins — $location() (defined in vendor/wheels/Global.cfc line 326) is not in scope. Every other helper call in this file goes through application.wo.$X(...); line 488 is the lone bare call. Lucee throws No matching function [$LOCATION] found, the application start aborts, and the engine discards the half-started app.
Why CI hasn't caught it
The non-dev smoke probes (#3044) boot directly into production/testing via environment.cfm; they never exercise the URL switch INTO production. The #3030/#3031 specs cover gate/flag resolution, not the post-switch cold start with redirectAfterReload=true.
Suggested fix
Change line 488 to application.wo.$location(url = local.url, addToken = false); (matching every other call in the file).
Acceptance criteria
From development with a reloadPassword set, ?reload=production&password=<secret> ends with the app serving in production (e.g. /wheels/info 404, SecurityHeaders emits the HSTS auto-default), no 500 during the transition.
Same for ?reload=maintenance.
wheels-errors.log contains no No matching function [$LOCATION] entries during the flow.
The redirectAfterReload=true + ?reload=true combination (explicitly set in development) also completes without throwing.
Regression spec covering the redirectAfterReload code path in onapplicationstart.cfc (the bare-call-vs-application.wo discrepancy is exactly the class of bug a structural spec could guard, like BareCfabortGuardSpec).
Evidence gathered during the security-hardening guide behavioral audit (Lucee 7 + Adobe 2023 docker harness).
Reported via guides: deployment/production-config.mdx, deployment/security-hardening.mdx
The report describes observable wrong behavior with a clear "what happened / what I expected": ?reload=production&password=<secret> 500s and silently reverts to the file-configured environment, with wheels-errors.log showing No matching function [$LOCATION] found. Verified against the tree: vendor/wheels/events/onapplicationstart.cfc is declared component { (no extends, no mixins), yet line 488 makes a bare $location(url = local.url, addToken = false) call. Every other helper call in that file (26 occurrences) goes through application.wo.$X(...), so $location() is genuinely out of scope at that call site — the reporter's root-cause analysis checks out.
Suspected layer
config — see .ai/wheels/security/ for the environment-switch / reload-hardening flow that exercises this path (reloadPassword, ?reload=<env>, redirectAfterReload). The defect itself lives in the application-start/environment-reload code at vendor/wheels/events/onapplicationstart.cfc.
Fix sketch
Single-file, mechanical: change vendor/wheels/events/onapplicationstart.cfc:488 from the bare $location(...) call to application.wo.$location(...), matching the established convention used by all 26 other helper calls in the file. The trigger is the redirectAfterReload=true (auto-enabled for production/maintenance by vendor/wheels/events/init/orm.cfm) + url.reload present branch. A structural regression guard (in the spirit of BareCfabortGuardSpec) catching bare in-scope helper calls in non-mixin event CFCs would prevent recurrence — that spec work belongs to propose-fix.
Confidence: high
The report pinpoints the exact line, the suspected layer is unambiguous, and the fix is a one-line change matching surrounding convention — independently verified by reading the file. No auto-downgrade rule strictly fires: the edit lands in vendor/wheels/events/**, not in vendor/wheels/security/**, middleware/**, a migration, or the DI container (auth has already succeeded by this redirect step), and the fix is uniform across all engines rather than engine-divergent.
The fix matches your root-cause analysis exactly: the lone bare $location() call in a no-helper-scope component {. The new structural guard (in the spirit of BareCfabortGuardSpec) fails the suite if any non-mixin event CFC ever again calls an out-of-scope framework helper without the application.wo. receiver. Local run: wheels.tests.specs.security went from 1 fail (pinpointing /events/onapplicationstart.cfc:488 ($location)) to 289 pass, 0 fail, 0 error on Lucee 7 + SQLite.
A human review is required before merge. The Reviewer will weigh in shortly. Doc updates (MDX guides, .ai/wheels/, CLAUDE.md) are handled separately by bot-update-docs.yml.
Activity
wheels-bot commentedon Jun 12, 2026
Wheels Bot — Triage
Classified as bug.
The report describes observable wrong behavior with a clear "what happened / what I expected":
?reload=production&password=<secret>500s and silently reverts to the file-configured environment, withwheels-errors.logshowingNo matching function [$LOCATION] found. Verified against the tree:vendor/wheels/events/onapplicationstart.cfcis declaredcomponent {(noextends, no mixins), yet line 488 makes a bare$location(url = local.url, addToken = false)call. Every other helper call in that file (26 occurrences) goes throughapplication.wo.$X(...), so$location()is genuinely out of scope at that call site — the reporter's root-cause analysis checks out.Suspected layer
config— see.ai/wheels/security/for the environment-switch / reload-hardening flow that exercises this path (reloadPassword,?reload=<env>,redirectAfterReload). The defect itself lives in the application-start/environment-reload code atvendor/wheels/events/onapplicationstart.cfc.Fix sketch
Single-file, mechanical: change
vendor/wheels/events/onapplicationstart.cfc:488from the bare$location(...)call toapplication.wo.$location(...), matching the established convention used by all 26 other helper calls in the file. The trigger is theredirectAfterReload=true(auto-enabled for production/maintenance byvendor/wheels/events/init/orm.cfm) +url.reloadpresent branch. A structural regression guard (in the spirit ofBareCfabortGuardSpec) catching bare in-scope helper calls in non-mixin event CFCs would prevent recurrence — that spec work belongs to propose-fix.Confidence:
highThe report pinpoints the exact line, the suspected layer is unambiguous, and the fix is a one-line change matching surrounding convention — independently verified by reading the file. No auto-downgrade rule strictly fires: the edit lands in
vendor/wheels/events/**, not invendor/wheels/security/**,middleware/**, a migration, or the DI container (auth has already succeeded by this redirect step), and the fix is uniform across all engines rather than engine-divergent.<!-- wheels-bot:triage:3054 -->
<!-- wheels-bot:triage-class:bug -->
<!-- wheels-bot:triage-confidence:high -->
wheels-bot commentedon Jun 12, 2026
Wheels Bot — Fix proposed
Draft PR: #3055
Spec:
vendor/wheels/tests/specs/security/EventHelperScopeGuardSpec.cfc— failing → passingImplementation:
vendor/wheels/events/onapplicationstart.cfc(line 488:$location(...)→application.wo.$location(...))The fix matches your root-cause analysis exactly: the lone bare
$location()call in a no-helper-scopecomponent {. The new structural guard (in the spirit ofBareCfabortGuardSpec) fails the suite if any non-mixin event CFC ever again calls an out-of-scope framework helper without theapplication.wo.receiver. Local run:wheels.tests.specs.securitywent from 1 fail (pinpointing/events/onapplicationstart.cfc:488 ($location)) to 289 pass, 0 fail, 0 error on Lucee 7 + SQLite.A human review is required before merge. The Reviewer will weigh in shortly. Doc updates (MDX guides,
.ai/wheels/,CLAUDE.md) are handled separately bybot-update-docs.yml.docs: add cross-engine invariant for bare event CFC helper scope (#3054)
fix(events): defer redirect-after-reload past onApplicationStart so U…