Describe the bug
On BoxLang, the lockingSpec :: releases lock even when callback throws an exception test fails on MySQL, Postgres, and SQLite with:
Expected [false] to be true
The spec verifies that after the locking callback throws, the lock is released. Lucee 6 and Lucee 7 pass this spec on the same three DBs — only BoxLang fails. Strongly suggests a BoxLang-specific try/finally semantic difference: the unlock path isn't executing when the callback raises.
Failing spec (BoxLang only)
wheels.model.lockingSpec :: releases lock even when callback throws an exception
Fails on: BoxLang × MySQL, BoxLang × Postgres, BoxLang × SQLite (3 DBs, same spec, same engine).
Passes on: Lucee 6 / Lucee 7 across all DBs.
Reproduction
tools/test-matrix.sh boxlang mysql
# or
curl 'http://localhost:60001/wheels/core/tests?db=mysql&format=json&directory=tests.specs.model'
Suspected cause
The locking implementation is likely structured as:
try {
acquireLock(...);
callback();
} finally {
releaseLock(...);
}
Or possibly using cflock / a CFC wrapper. BoxLang may not be running the finally block when the callback throws — or the implementation uses an exception-handling shape (e.g., try/catch without re-throw, or a CFC-method-level handler) that doesn't behave identically on BoxLang.
Locate the locking impl that backs this spec — probably vendor/wheels/model/locking.cfc (or similar) — and verify the cleanup path runs on BoxLang under thrown exception. May need restructuring to use plain try/finally if it currently uses something more exotic.
Evidence
Compat-matrix run 25978222394 (develop, 2026-05-17):
boxlang/mysql: 1 fail (this spec)
boxlang/postgres: 1 fail (this spec)
boxlang/sqlite: 1 fail (this spec)
lucee6/<same DBs>: passes
lucee7/<same DBs>: passes
Expected behavior
Lock is released after callback throws — spec passes on BoxLang on the same DBs that Lucee passes on.
Related
Desktop
Describe the bug
On BoxLang, the
lockingSpec :: releases lock even when callback throws an exceptiontest fails on MySQL, Postgres, and SQLite with:The spec verifies that after the locking callback throws, the lock is released. Lucee 6 and Lucee 7 pass this spec on the same three DBs — only BoxLang fails. Strongly suggests a BoxLang-specific
try/finallysemantic difference: the unlock path isn't executing when the callback raises.Failing spec (BoxLang only)
Fails on: BoxLang × MySQL, BoxLang × Postgres, BoxLang × SQLite (3 DBs, same spec, same engine).
Passes on: Lucee 6 / Lucee 7 across all DBs.
Reproduction
Suspected cause
The locking implementation is likely structured as:
try { acquireLock(...); callback(); } finally { releaseLock(...); }Or possibly using
cflock/ a CFC wrapper. BoxLang may not be running thefinallyblock when the callback throws — or the implementation uses an exception-handling shape (e.g.,try/catchwithout re-throw, or a CFC-method-level handler) that doesn't behave identically on BoxLang.Locate the locking impl that backs this spec — probably
vendor/wheels/model/locking.cfc(or similar) — and verify the cleanup path runs on BoxLang under thrown exception. May need restructuring to use plaintry/finallyif it currently uses something more exotic.Evidence
Compat-matrix run 25978222394 (develop, 2026-05-17):
boxlang/mysql: 1 fail (this spec)boxlang/postgres: 1 fail (this spec)boxlang/sqlite: 1 fail (this spec)lucee6/<same DBs>: passeslucee7/<same DBs>: passesExpected behavior
Lock is released after callback throws — spec passes on BoxLang on the same DBs that Lucee passes on.
Related
Desktop