laravel/framework · error · RuntimeException

Transactions Manager has not been set.

Error message

Transactions Manager has not been set.

What it means

Thrown by Connection::afterCommit (and afterRollBack) when $this->transactionsManager is null. Laravel's transaction lifecycle relies on a TransactionsManager instance to register callbacks that must fire after commit; if it was never set on the connection, afterCommit cannot schedule the callback and throws RuntimeException.

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 bd6b5437e6)

Solutions

  1. Obtain the connection through the DatabaseManager (DB::connection()) so the transactions manager is set automatically.
  2. Inject/call $connection->setTransactionManager($manager) if you construct connections manually.
  3. Guard the call: if (DB::transactionLevel() > 0) DB::afterCommit($cb); else $cb(); to fire immediately when not in a transaction.
  4. In tests, use Illuminate\Foundation\Testing\RefreshDatabase or the in-memory SQLite via the framework so the manager is bootstrapped.

Example fix

// before
$conn = new Illuminate\Database\MySqlConnection($pdo, '', '');
$conn->afterCommit(fn () => event(new OrderShipped));
// throws 'Transactions Manager has not been set.'

// after
$conn = DB::connection(); // manager wired by framework
$conn->afterCommit(fn () => event(new OrderShipped));
Defensive patterns

Strategy: validation

Validate before calling

$conn = DB::connection();
if (! $conn->getTransactionManager()) {
    // manager missing; fire callback immediately or wire the manager
    $cb();
    return;
}
$conn->afterCommit($cb);

Type guard

function connectionHasTransactionManager(\Illuminate\Database\Connection $c): bool
{
    return method_exists($c, 'getTransactionManager') && $c->getTransactionManager() !== null;
}

Try / catch

try {
    DB::afterCommit($cb);
} catch (\RuntimeException $e) {
    if (str_contains($e->getMessage(), 'Transactions Manager has not been set')) {
        $cb(); // fire immediately when outside framework
    } else throw $e;
}

Prevention

When it happens

Trigger: Calling DB::afterCommit(fn () => ...) on a connection where the transactions manager was not wired (e.g. a manually-constructed Connection, a custom connection extending Connection, or test setups using DB::connection without bootstrapping the manager).

Common situations: Unit tests constructing a bare Connection or using an in-memory driver that skips the manager; custom database connection classes that override setTransactionManager or never receive one; package that creates connections directly bypassing the DatabaseManager; calling afterCommit outside a transactional context after the manager was reset.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/c24ecb7682619974.json. Report an issue: GitHub.