On January 3, 2026, a 3,000-user load test against IBM ContextForge left PostgreSQL connections stuck in idle in transaction until the pool ran dry. The cause was three lines of cleanup code. We rewound the repository to the code as it stood before the fix, gave Tomosu that one file and nothing else, and ran a blind scan. Tomosu named the same weakness and proposed a fix that makes connection release unconditional.
A connection leak that took a 3,000-user load test to expose was also identifiable from the application source alone.
- The defect: in
mcpgateway/middleware/token_scoping.py,db.close()ran only ifdb.commit()succeeded, so a failing commit left the connection unreleased (issue #1885). - The fix: wrap the commit so the close always runs (PR #1886). Under the same load, stuck connections dropped to zero.
- The blind scan: flagged an unsafe database-session lifecycle where an operation before close can fail and leave the connection unreleased.
The system under test
ContextForge is an open-source AI gateway and registry for MCP, A2A, REST and gRPC. AI agents, applications and copilots call it, and it routes, authenticates, scopes tokens and federates tools to downstream servers. Every request opens a database session against a PostgreSQL connection pool with bounded capacity. That puts it squarely in a high-concurrency path.
What the load test found
The team ran a test with 3,000 concurrent users, designed to expose behaviour that never appears during ordinary development. Requests looked healthy, but PostgreSQL connections stopped cycling normally. Between 42 and 81 connections sat in idle in transaction: occupied, doing no useful work, and unavailable for reuse. Each one could stay stuck for up to 120 seconds before a timeout intervened. Two minutes is an eternity when thousands of requests are competing for a limited pool.
Each stage of the failure is ordinary. The amplification is not.
- 3,000 concurrent requests arrive
- Each opens a database session from a finite pool
- Some connections are never released
- The pool runs out of capacity
- Latency, errors and upstream cascading failures
The code: a cleanup that wasn't guaranteed
The investigation led to the session cleanup in token_scoping.py. It looks reasonable: a finally block, a commit, a close. The intent is clearly to clean up the session whatever happened earlier.
finally:
db.commit() # can raise
db.close() # never reached if commit raises
But finally does not mean every statement inside it is guaranteed to run. db.commit() is itself an operation that can fail. If it raises, Python leaves the block immediately and execution never reaches close(). Three lines, under enough concurrency, become pool exhaustion.
The fix: make release unconditional
PR #1886 nests the commit in its own try so the close survives a failing commit. The implementation change is tiny. The conceptual change is not.
finally:
try:
db.commit()
finally:
db.close() # always runs
Under the same 3,000-user load, the result changed completely:
| Before the fix | After the fix | |
|---|---|---|
| Stuck connections | 42–81 | 0 |
| Connection release | Held up to 120 s | Cycling in 1–2 s |
| Pool state | Exhausted | Healthy |
The rule underneath it: if you acquire a finite production resource, its release must survive every relevant failure path.
The experiment: could Tomosu have caught it first?
Everything the team learned came from production-scale conditions. We wanted to know whether Tomosu could surface the same weakness from the code, before any load test. We were not asking Tomosu to review the patch. We checked out commit cf5adcd5d, the code exactly as it stood before the remediation existed, and gave Tomosu one file: mcpgateway/middleware/token_scoping.py, 755 lines, 32 KB.
- Issue #1885
- PR #1886
- The fix
- Load-test results
- Idle-in-transaction diagnosis
- Release notes
- Any instruction on what to look for
Before scanning, we locked the success criterion so the result could not be reinterpreted afterwards:
Identify unsafe database-session cleanup where an operation before close() can fail and prevent reliable connection release.
Direct hit: names the unsafe session lifecycle on this path. Adjacent: generic exception-handling or database advice. Miss: anything else.
The result: a direct hit
Unsafe database-session lifecycle
“An operation performed before the session is closed can fail, leaving the connection unreleased.”
Scored against the locked criterion, the finding names the database-session cleanup path, states that the preceding operation can fail, and ties it to unreliable connection release. All three checks pass.
Finding on token_scoping.py, identified from the historical source alone, with no incident context.
Tomosu's recommended change removes the commit from the cleanup entirely, because this is a read-oriented path that needs no commit. Connection release becomes unconditional.
Three versions, one invariant
finally:
db.commit()
db.close()Release depends on commitfinally:
try:
db.commit()
finally:
db.close()Commit kept, close protectedfinally:
db.close()Commit dependency removedDifferent code, same reliability property: release must not depend on commit succeeding. Tomosu had not seen the patch.
Two paths to the same weakness
One path ran a 3,000-user load test, observed the failure, investigated and located the defect. The other read the historical source and identified the weakness with no incident context. Static analysis does not replace load testing. It moves some of the learning earlier, to the pull request, where fixing it costs three lines instead of an outage.
- Code
- →
- Deploy
- →
- Runtime
- →
- Back to code
Reliability is a lifecycle, not a one-time code review. Resource-lifecycle analysis in code, readiness context at deploy, production signals at runtime, and runtime insight fed back into the next change.
Get the full forensics deck
22 slides, PDF
ContextForge is an open-source project. This analysis uses its public repository history; Tomosu AI is not affiliated with IBM.
What will your load test find, and could your code tell you first? Run a free PRI scan on any GitHub repository.