phalcon/cphalcon · error · Phalcon\DataMapper\Pdo\Exception\CannotDisconnect

Cannot disconnect a Decorated connection instance

Error message

Cannot disconnect a Decorated connection instance

What it means

Connection\Decorated wraps an already-constructed \PDO instance. The wrapper does not own the underlying connection's lifecycle — connect() is a no-op ('already connected') and disconnect() always throws CannotDisconnect, because closing the shared PDO is the original owner's job.

Source

Thrown at phalcon/DataMapper/Pdo/Connection/Decorated.zep:64

        this->setProfiler(profiler);
    }

    /**
     * Connects to the database.
     */
    public function connect() -> void
    {
        // already connected
    }

    /**
     * Disconnects from the database; disallowed with decorated PDO connections.
     *
     * @throws CannotDisconnect
     */
    public function disconnect() -> void
    {
        throw new CannotDisconnect(
            "Cannot disconnect a Decorated connection instance"
        );
    }
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Skip teardown for wrapped instances: if (!$conn instanceof Connection\Decorated) { $conn->disconnect(); }
  2. Let the code that created the \PDO manage its lifecycle (null the reference where it was constructed)
  3. In pools, drop the reference instead of calling disconnect() on decorated connections
  4. Make ownership explicit in design: whoever news up the \PDO destroys it

Example fix

// before
foreach ($this->connections as $conn) {
    $conn->disconnect(); // CannotDisconnect on Decorated
}

// after
foreach ($this->connections as $conn) {
    if (!$conn instanceof \Phalcon\DataMapper\Pdo\Connection\Decorated) {
        $conn->disconnect();
    }
}
Defensive patterns

Strategy: type-guard

Type guard

use Phalcon\DataMapper\Pdo\Connection\Decorated;

function canDisconnect(object $connection): bool
{
    return !$connection instanceof Decorated;
}

// foreach ($connections as $conn) { if (canDisconnect($conn)) $conn->disconnect(); }

Try / catch

use Phalcon\DataMapper\Pdo\Connection\Decorated;
use Phalcon\DataMapper\Pdo\Exception\CannotDisconnect;

try {
    $connection->disconnect();
} catch (CannotDisconnect $e) {
    // wrapped PDO: lifecycle belongs to the code that created it; just drop the reference
}

Prevention

When it happens

Trigger: $decorated = new Decorated($pdo); $decorated->disconnect(); teardown/pool code that iterates all connections and calls disconnect() on each; reusing shutdown logic written for Connection against a Decorated instance.

Common situations: Connection registries or pools holding mixed Connection and Decorated instances; long-lived shared PDO handed to several components; test tear-down that disconnects everything it created.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/03e031b84d08baf0. Report an issue: GitHub.