no-transaction-on-pool
Prevents running transaction commands directly on pool (must use dedicated client).
Keywords: transactions, race condition, CWE-362, pg, node-postgres, pool
Prevents running transaction commands directly on pool (must use dedicated client).
⚠️ This rule errors by default in the recommended config.
Quick Summary
| Aspect | Details |
|---|---|
| CWE Reference | CWE-362 (Race Condition) |
| Severity | High (CVSS: 7.5) |
| Category | Correctness |
Rule Details
pool.query() acquires a different client for each call. Transaction commands (BEGIN, COMMIT, ROLLBACK) on pool may execute on different connections, breaking transaction semantics.
❌ Incorrect
// Each query might use a different connection!
await pool.query('BEGIN');
await pool.query('INSERT INTO users VALUES ($1)', [user]);
await pool.query('COMMIT'); // May commit nothing✅ Correct
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query('INSERT INTO users VALUES ($1)', [user]);
await client.query('COMMIT');
} catch (e) {
await client.query('ROLLBACK');
throw e;
} finally {
client.release();
}Error Message Format
⚠️ CWE-362 | Transaction command on pool causes race condition | HIGH
Fix: Use pool.connect() and run transaction commands on the returned clientWhen Not To Use It
- Never disable this rule - transactions on pool are always incorrect
Known False Negatives
The following patterns are not detected due to static analysis limitations:
Aliased Pool Reference
Why: The rule tracks pool.query() patterns; renamed references are missed.
// ❌ NOT DETECTED - Aliased pool
const db = pool;
await db.query('BEGIN'); // 'db' not recognized as poolMitigation: Use consistent naming for database pools. Add custom pool identifiers via configuration.
Dynamic Query String
Why: Transaction commands in variables are not detected.
// ❌ NOT DETECTED - Query from variable
const cmd = 'BEGIN';
await pool.query(cmd);Mitigation: Use literal query strings for transaction commands.
Wrapped Pool Methods
Why: Wrapper functions hide pool access.
// ❌ NOT DETECTED - Transaction in wrapper
async function runQuery(sql: string) {
return pool.query(sql);
}
await runQuery('BEGIN'); // Wrapper not tracedMitigation: Apply rule to all modules. Use dedicated transaction wrappers that enforce client pattern.
Transaction Commands in Template Literals
Why: Complex template literals may hide transaction keywords.
// ❌ NOT DETECTED - Hidden in template
const action = 'BEGIN';
await pool.query(`${action}`);Mitigation: Use explicit transaction management patterns. Create utility functions that enforce correct usage.
Related Rules
- no-missing-client-release - Ensures client release