symfony/http-foundation · error · DomainException

Transactional locks are currently not implemented for PDO…

Error message

Transactional locks are currently not implemented for PDO driver "%s".

What it means

This DomainException comes from PdoSessionHandler::getSelectSql() when lock_mode is LOCK_TRANSACTIONAL and the PDO driver is neither mysql, pgsql, oci, sqlsrv, nor sqlite. getSelectSql() builds the row-locking SELECT (FOR UPDATE / WITH (UPDLOCK, ROWLOCK)) per driver; an unrecognized driver has no known row-lock syntax, so the handler throws instead of silently reading without a lock. It is reached from doRead() during session_start().

Solutions

  1. Use a supported driver/DSN: switch pdo_dblib to pdo_sqlsrv ('sqlsrv:') for SQL Server, or use mysql/pgsql/oci/sqlite.
  2. If row-level locking is genuinely unavailable, set 'lock_mode' => PdoSessionHandler::LOCK_NONE (accepting weaker concurrency guarantees).
  3. Log/inspect (new PDO(...))->getAttribute(PDO::ATTR_DRIVER_NAME) to confirm which driver name the handler sees and align the DSN accordingly.
  4. Subclass PdoSessionHandler and override getSelectSql()/doRead() to emit correct locking SQL for your driver.

Example fix

// before (FreeTDS driver not supported)
$pdo = new PDO('dblib:host=mssql;dbname=app', $user, $pass);

// after
$pdo = new PDO('sqlsrv:Server=mssql;Database=app', $user, $pass);
Defensive patterns

Strategy: validation

Validate before calling

$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$supported = ['mysql', 'pgsql', 'oci', 'sqlsrv', 'sqlite'];
if (!in_array($driver, $supported, true)) {
    $options['lock_mode'] = PdoSessionHandler::LOCK_NONE; // or switch driver
}

Try / catch

try {
    $session->start();
} catch (\DomainException $e) {
    if (str_contains($e->getMessage(), 'Transactional locks are currently not implemented')) {
        // fall back to a driver-appropriate handler (e.g. LOCK_NONE or native files)
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: PdoSessionHandler on a PDO driver other than mysql/pgsql/oci/sqlsrv/sqlite (e.g. dblib for SQL Server, ibm, custom PDO subclass) with the default LOCK_TRANSACTIONAL lock mode (or lock_mode explicitly set to it), then opening a session.

Common situations: Connecting to SQL Server via pdo_dblib (FreeTDS) instead of pdo_sqlsrv, so ATTR_DRIVER_NAME reports 'dblib'; exotic PDO drivers; misconfigured DSNs that pick an unexpected driver; frameworks bundle config moved to a different database platform.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of symfony/http-foundation@5aea19cd67 (2026-09-13). Data as JSON: /api/errors/8b496fca9f6d80e7. Report an issue: GitHub.

Appendix: source

Thrown at Session/Storage/Handler/PdoSessionHandler.php:849

     * @throws \DomainException When an unsupported PDO driver is used
     */
    private function getSelectSql(): string
    {
        if (self::LOCK_TRANSACTIONAL === $this->lockMode) {
            $this->beginTransaction();

            switch ($this->driver) {
                case 'mysql':
                case 'oci':
                case 'pgsql':
                    return "SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WHERE $this->idCol = :id FOR UPDATE";
                case 'sqlsrv':
                    return "SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WITH (UPDLOCK, ROWLOCK) WHERE $this->idCol = :id";
                case 'sqlite':
                    // we already locked when starting transaction
                    break;
                default:
                    throw new \DomainException(\sprintf('Transactional locks are currently not implemented for PDO driver "%s".', $this->driver));
            }
        }

        return "SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WHERE $this->idCol = :id";
    }

    /**
     * Returns an insert statement supported by the database for writing session data.
     */
    private function getInsertStatement(#[\SensitiveParameter] string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement
    {
        switch ($this->driver) {
            case 'oci':
                $data = fopen('php://memory', 'r+');
                fwrite($data, $sessionData);
                rewind($data);
                $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :expiry, :time) RETURNING $this->dataCol into :data";
                break;

View on GitHub (pinned to 5aea19cd67)