laravel/framework · error · RuntimeException
Transactions Manager has not been set.
Error message
Transactions Manager has not been set.
What it means
RuntimeException from afterCommit() when the transactions manager ($transactionsManager) is not set on the connection. afterCommit() defers a callback until the surrounding transaction commits; without a manager to track transaction state there is nothing to defer onto, so the call is rejected rather than silently dropped.
Solutions
- Guard the call: only register an afterCommit callback when inside a transaction, e.g. if (DB::connection()->transactionLevel() > 0) { ... } else { run it immediately }.
- Wrap the work in DB::transaction() so a transactions manager is established before afterCommit is called.
- If the callback should run regardless, skip afterCommit and run the logic directly (or dispatch a job).
- Ensure the connection is fully bootstrapped via the standard Laravel DB facade/service-provider wiring.
Example fix
// before
// in an observer, called from a queue worker with no DB transaction
DB::connection()->afterCommit(fn () => Cache::forget("user:{$user->id}"));
// after
if (DB::connection()->transactionLevel() > 0) {
DB::connection()->afterCommit(fn () => Cache::forget("user:{$user->id}"));
} else {
Cache::forget("user:{$user->id}");
} Defensive patterns
Strategy: validation
Validate before calling
// Only register afterCommit callbacks when a transaction (and its manager) is active.
$conn = DB::connection();
if ($conn->transactionLevel() > 0) {
$conn->afterCommit($callback);
} else {
// no transaction: run immediately, or dispatch a job
$callback();
} Type guard
function afterCommitIsSafe(\Illuminate\Database\ConnectionInterface $conn): bool
{
// The transactions manager is set whenever a transaction has been started.
return $conn instanceof \Illuminate\Database\Connection && $conn->transactionLevel() > 0;
} Try / catch
try {
DB::connection()->afterCommit($callback);
} catch (\RuntimeException $e) {
if (str_contains($e->getMessage(), 'Transactions Manager has not been set')) {
// either open a transaction first, or run the callback directly
$callback();
} else {
throw $e;
}
} Prevention
- Use the framework's DB::transaction() helper so the manager is always initialized.
- In observers/listeners that may run from queue workers or CLI, guard afterCommit with transactionLevel().
- Prefer dispatching a job over afterCommit when the side effect must run regardless of transaction state.
When it happens
Trigger: Calling DB::connection()->afterCommit(...) outside of any transaction context; calling afterCommit on a connection before a transaction manager is attached (e.g. in low-level/CLI bootstrapping or with a custom connection); using a connection type that does not initialize the transactions manager.
Common situations: Model observers/listeners calling afterCommit when invoked from a queue worker or CLI command with no active DB transaction; testing with a connection that bypasses normal Laravel bootstrapping; using afterCommit where you actually mean after the immediate save regardless of transactions.
Related errors
- A driver must be specified.
- Database connection [ ] not configured.
- Database file at path
- Database hosts array is empty.
- {$e->getMessage()}
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/c24ecb7682619974.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Database/Concerns/ManagesTransactions.php:360
{
return $this->transactions;
}
/**
* Execute the callback after a transaction commits.
*
* @param callable $callback
* @return void
*
* @throws \RuntimeException
*/
public function afterCommit($callback)
{
if ($this->transactionsManager) {
return $this->transactionsManager->addCallback($callback);
}
throw new RuntimeException('Transactions Manager has not been set.');
}
/**
* Execute the callback after a transaction rolls back.
*
* @param callable $callback
* @return void
*
* @throws \RuntimeException
*/
public function afterRollBack($callback)
{
if ($this->transactionsManager) {
return $this->transactionsManager->addCallbackForRollback($callback);
}
throw new RuntimeException('Transactions Manager has not been set.');
}View on GitHub (pinned to e0f6eb3518)