{"record":{"id":"58d2321e481df529","repo":"phalcon/cphalcon","slug":"there-is-no-active-transaction","errorCode":null,"errorMessage":"There is no active transaction","messagePattern":"There is no active transaction","errorType":"exception","errorClass":"Phalcon\\Db\\Exceptions\\NoActiveTransaction","httpStatus":null,"severity":"error","filePath":"phalcon/Db/Adapter/Pdo/AbstractPdo.zep","lineNumber":169,"sourceCode":"        if typeof eventsManager == \"object\" {\n            eventsManager->fire(\"db:createSavepoint\", this, savepointName);\n        }\n\n        return this->createSavepoint(savepointName);\n    }\n\n    /**\n     * Commits the active transaction in the connection\n     */\n    public function commit(bool nesting = true) -> bool\n    {\n        var eventsManager, savepointName;\n\n        /**\n         * Check the transaction nesting level\n         */\n        if this->transactionLevel === 0 {\n            throw new NoActiveTransaction();\n        }\n\n        if this->transactionLevel === 1 {\n            /**\n             * Notify the events manager about the committed transaction\n             */\n            let eventsManager = <ManagerInterface> this->eventsManager;\n            if typeof eventsManager == \"object\" {\n                eventsManager->fire(\"db:commitTransaction\", this);\n            }\n\n            /**\n             * Reduce the transaction nesting level\n             */\n            let this->transactionLevel--;\n\n            return this->pdo->commit();\n        }","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Db/Adapter/Pdo/AbstractPdo.zep#L151-L187","documentation":"commit() requires the adapter's internal transactionLevel to be at least 1; level 0 means no begin() is outstanding on this adapter instance and NoActiveTransaction is thrown. Each adapter object tracks its own nesting counter, so the check is bookkeeping-local: it does not ask the server whether a transaction is open.","triggerScenarios":"commit() without a prior successful begin(); double commit (commit, then commit again in a finally block); rollback already ran in the catch path, decremented the level to 0, and a finally then calls commit; calling commit() on a different adapter instance than the one that called begin().","commonSituations":"finally blocks that both roll back on error and commit on success, arranged so both run; layered transaction wrappers (service + repository each finalizing); long-lived workers where a previous exception already unwound the transaction; tests that reuse an adapter across cases without resetting state.","solutions":["Guard the finalize step: if ($connection->isUnderTransaction()) { $connection->commit(); }","Structure the unit of work so exactly one of commit/rollback executes per begin() (commit in try is an anti-pattern — commit at the end of try, rollback in catch, and never both)","Confirm begin() succeeded (it returns bool) before doing work that will be committed"],"exampleFix":"// before\ntry {\n    $connection->begin();\n    work($connection);\n} catch (\\Throwable $e) {\n    $connection->rollback();\n    throw $e;\n} finally {\n    $connection->commit(); // runs after rollback too -> throws\n}\n\n// after\n$connection->begin();\ntry {\n    work($connection);\n    $connection->commit();\n} catch (\\Throwable $e) {\n    if ($connection->isUnderTransaction()) {\n        $connection->rollback();\n    }\n    throw $e;\n}","handlingStrategy":"validation","validationCode":"if ($connection->isUnderTransaction()) {\n    $connection->commit();\n} else {\n    $logger->warning('commit() skipped: no active transaction');\n}","typeGuard":null,"tryCatchPattern":"use Phalcon\\Db\\Exceptions\\NoActiveTransaction;\n\ntry {\n    $connection->commit();\n} catch (NoActiveTransaction $e) {\n    // already finalized elsewhere — log and continue\n    $logger->warning($e->getMessage());\n}","preventionTips":["Commit at the end of try, rollback in catch — never in finally — so only one finalize runs per begin()","Guard finalization with isUnderTransaction() / getTransactionLevel() > 0 in any wrapper that may double-finalize","Check begin()'s boolean return before doing transactional work"],"tags":["php","phalcon","db","transaction","commit","transaction-lifecycle"],"backgroundTag":"no-active-transaction","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}