Skip to content

Bug: MySQL errno 1213 leaves transDepth set so the next write autocommits #10649

Open

Description

@KevinBlakeLopez

PHP Version

8.5

CodeIgniter4 Version

4.7.5 (measured in a lab). Still present on develop at df8b96bee (4.7.6-dev) by source read: MySQLi\Connection::execute() does not treat errno 1213 specially, and transCommit() returns true when mysqli::commit() returns true.

CodeIgniter4 Installation Method

Git

Which operating systems have you tested for this bug?

macOS

Which server did you use?

cli

Environment

testing

Database

MySQL 8.4.11, MySQLi, mysqlnd. InnoDB. No production failure has been observed. This is a lab measurement.

What happened?

Errno 1213 is ER_LOCK_DEADLOCK (Deadlock found when trying to get lock; try restarting transaction). InnoDB has already rolled the victim transaction back. CodeIgniter leaves transDepth at 1.

Measured on CodeIgniter 4.7.5:

  1. The victim transaction is rolled back by InnoDB. The victim row is gone.
  2. transDepth stays 1.
  3. A later insert on that same connection autocommits.
  4. transComplete() returns false and does not undo that insert.
  5. transCommit() returns true while the victim row is absent.
  6. mysqli::commit() returns true in the same situation. CodeIgniter treats that true as a successful commit of the transaction it still has open.

transComplete() sees transStatus === false (because query() called handleTransStatus()) and calls transRollback(). The later insert is already committed, so that rollback does not remove it. transCommit() does not look at transStatus. It calls _transCommit() → mysqli::commit(), which returns true, then decrements transDepth and returns true.

Errno 1205 is not this bug. It was measured separately. The message is try restarting transaction both when innodb_rollback_on_timeout is OFF and when it is ON, and those two settings leave the transaction in different states. This report is only errno 1213, where InnoDB has rolled the victim back.

Steps to Reproduce

  1. Two connections, InnoDB tables, two rows that can be locked in opposite orders.
  2. On the victim connection, transBegin() and insert a row that exists only inside that transaction.
  3. Produce errno 1213 on that connection (Deadlock found when trying to get lock).
  4. Observe transDepth === 1 and the victim row already absent.
  5. Insert a second row on that same connection.
  6. That second row is visible from another connection (autocommit).
  7. transComplete() returns false and the second row is still present.
  8. On a fresh run of steps 1–5, transCommit() returns true while the victim row is absent.

Expected Output

After InnoDB has rolled the victim back, a following write on that connection must not autocommit. transCommit() must not return true while the victim row is absent.

Anything else?

Searched issues and pull requests, open and closed, before opening this. Nothing already covers this defect.

Neighbors that do not:

Please do not fold errno 1205 into a fix for this issue.

Activity

  1. added 4 commits that reference this issue on Oct 22, 2026
    81f02e6
    8089966
    dcb991d
    5cd609b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions