TESTBOX-453: Fix BoxLang CLI runner misreading its own path as a bundle argument - #201
Merged
Merged
Conversation
The `run` launcher resolved its own directory to an absolute path before invoking `boxlang`, so BoxLangRunner.bx was executed via an absolute filesystem path. BoxLang 1.17.0 hardened path resolution to force absolute-looking paths through mappings/webroot instead of the OS filesystem, which intermittently broke the entry point's own self-resolution later in the run (surfacing as a ClassNotFoundBoxLangException during TestBox's bundle discovery) on CI runners invoking `./testbox/run`. Passing boxlang a relative path avoids exercising that code path, and leaves server.cli.executionPath pointing at the caller's working directory as before.
Installed BoxLang v1.17.0+58 (the exact engine build from the CI
failure reports) and reproduced the crash locally with a scratch
project mirroring bx-sites' setup. Instrumented TestBox.cfc and
BoxLangRunner.bx to trace the failure and found the real cause:
`server.cli.parsed.positionals` on this engine build always includes
the entry-point script's own invocation path as its first entry
(effectively an argv[0] leak), regardless of whether boxlang was
invoked with a relative or absolute path.
BoxLangRunner.bx's `if( positional.len() ) { initArgs.bundles =
positional[1] }` therefore always treats a plain `./testbox/run
--verbose --stream` invocation (no bundle argument) as if the user
had passed the runner's own path as a bundle to test, which then
fails GetClassMetadata() resolution downstream in TestBox.cfc's
bundle-discovery loop with the reported ClassNotFoundBoxLangException.
This supersedes the previous commit on this branch, which changed
`run` to pass a relative path under the theory that BoxLang 1.17.0's
include-path hardening was responsible. That was disproven by testing:
the crash reproduces identically with a relative invocation, and the
real fix below resolves it under both relative and absolute
invocation. `run` is reverted to its original form.
Fix: filter `server.cli.parsed.positionals` to drop any entry that
resolves (relative to the invocation directory, following symlinks)
to this same script, before treating what remains as a user-supplied
bundle argument. Verified locally: 8/8 consecutive green runs via
`./testbox/run --stream`, and explicit `run my.bundle`-style
invocations still work correctly.
lmajano
pushed a commit
to ortus-boxlang/bx-sites
that referenced
this pull request
Aug 29, 2026
tests.yml's test suite was intermittently failing before a single spec ran, with ClassNotFoundBoxLangException on TestBox's own BoxLangRunner.bx - blocking this PR's own CI (and any other PR's) independently of the registerMapping fix above. Root cause turned out to be a real TestBox bug, not a BoxLang engine issue: server.cli.parsed.positionals leaks the runner's own invocation path as argv[0] on current engine builds, and BoxLangRunner.bx's naive `positional[1]` grab misread that as a user-supplied bundle argument whenever none was actually given. Fixed upstream in Ortus-Solutions/TestBox#201 (reproduced and verified locally there). Pin id=testbox to id=testbox@be so CI picks up that fix from the bleeding-edge channel now, rather than waiting on a tagged stable TestBox release. Revert to the unpinned id=testbox once one ships it.
This was referenced Aug 29, 2026
Closed
lmajano
added a commit
that referenced
this pull request
Aug 29, 2026
#202) Reported by the maintainer running ./testbox/run --stream --verbose against BoxLang v1.17.0+58: every CLI run crashed immediately after the recent CLI-runner fix (#201) cleared the way to reach this code, with: KeyNotFoundException: The requested key [url] was not located in any scope or it's undefined at ...ScriptingRequestBoxContext.scopeFind at ...Testbox$cfc.invokeFunction_runRaw(TestBox.cfc:408) Root cause: runRaw() and dryRun() unconditionally reference the `url` scope to support web-request query-string test filters (?testBundles=, ?testSuites=, etc.). The `url` scope only exists in a real HTTP request context - it is never registered at all when TestBox runs via the BoxLang CLI. #200 ("support full null runtimes") added a `structKeyExists( url, "testBundles" )` guard, but that doesn't help here: resolving the bare `url` identifier itself is what throws - structKeyExists() never gets a chance to run, since BoxLang has to look up `url` as a scope before it can pass it as an argument. Fix: skip these URL-based filter blocks entirely when variables.IS_CLI is true (already computed at class init). CLI users already have --filter-bundles/--filter-suites/--filter-specs for the same purpose via BoxLangRunner.bx, so nothing is lost. Verified locally against BoxLang v1.17.0+58: reproduced the exact reported crash against the real merged development branch first (structKeyExists guard included), then confirmed the fix with the maintainer's exact command (./testbox/run --streamingj --verbose, 4/4 clean runs), plus --dry-run and --stream, which exercise both patched call sites (runRaw() and dryRun()). Co-authored-by: Claude <noreply@anthropic.com>
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
./testbox/run --verbose --stream(the BoxLang CLI runner) fails immediately, before any test spec runs, with:This surfaced downstream in
ortus-boxlang/bx-sitesCI onubuntu-latest, reported as intermittent (~1/3 of runs) against BoxLang engine build v1.17.0+58.Root cause: On the affected BoxLang build,
server.cli.parsed.positionalsalways includes the entry-point script's own invocation path as its first entry (an argv[0]-style leak), regardless of whetherboxlangwas invoked with a relative or absolute path.BoxLangRunner.bx's CLI handling assumed any non-emptypositionalsmeant the user passed a bundle name positionally:Since
positionalsis never actually empty on this engine build, an ordinary./testbox/run --verbose --streaminvocation (no bundle argument) haspositional[1]equal to the runner's own script path, so TestBox is told to test its own runner file as a "bundle" — which then fails to resolve as a class inTestBox.cfc's bundle-discovery loop.I reproduced this locally 100% of the time (installed BoxLang v1.17.0+58 via the quick installer and built a scratch project mirroring bx-sites), traced it with instrumentation, and confirmed the fix resolves it under both relative and absolute
boxlanginvocation, with 8/8 consecutive green runs afterward.Fix: filter
server.cli.parsed.positionalsto drop any entry that resolves (relative toserver.cli.executionPath, following symlinks) to the currently-executing script, before treating what remains as a genuine user-supplied bundle argument.Jira Issues
https://ortussolutions.atlassian.net/browse/TESTBOX-453
Type of change
Checklist
Note: this fix touches the CLI runner's argument parsing, which isn't exercised by TestBox's existing test suite (that runs against CFML engine web servers, not the BoxLang CLI entry point) — verification here was a manual local repro against the actual BoxLang engine build, described above and in the linked Jira issue.
Generated by Claude Code