Sitelet https://github.com/googleapis/google-cloud-python/pull/19066
Skip to content

fix(firestore): retry commits when the transaction has expired - #19066

Open
pcbeingused333 wants to merge 1 commit into
googleapis:mainfrom
pcbeingused333:fix-firestore-retry-expired-transaction
Open

pcbeingused333 wants to merge 1 commit into
googleapis:mainfrom
pcbeingused333:fix-firestore-retry-expired-transaction

Conversation

@pcbeingused333

Copy link
Copy Markdown

Fixes #19063

Root cause. _Transactional.__call__ and _AsyncTransactional.__call__ retry a commit only when it raises Aborted. Once a Firestore transaction id expires, the backend returns InvalidArgument with the message "The referenced transaction has expired or is no longer valid." That error falls through to rollback, so the transaction fails instead of restarting. The Node and Java clients retry this specific message.

Fix. A commit that raises Aborted, or InvalidArgument whose text contains "transaction has expired", now restarts the transaction with the same retry id already used for Aborted. Any other InvalidArgument is still raised immediately and the transaction is rolled back. Read-only transactions are not retried. Backoff and the attempt limit are unchanged. The check is _is_retryable_commit_error, shared by the sync and async wrappers.

Test. The existing second-attempt success case is repeated with the first commit raising InvalidArgument("The referenced transaction has expired or is no longer valid."): two commits, no rollback, and the wrapped callable runs twice. A second case raises InvalidArgument("other") and asserts one commit plus rollback. The same pair covers the async wrapper.


This PR was prepared with the help of an AI assistant; the changes were tested as described above.

Firestore returns InvalidArgument, not Aborted, once a transaction id
expires. Retry that message the way the Node and Java clients do, and
leave every other InvalidArgument as a hard failure.
@pcbeingused333
pcbeingused333 requested a review from a team as a code owner November 13, 2026 07:28

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds support for retrying transactions when they fail due to an expired transaction ID, which Firestore reports as an InvalidArgument exception. This is implemented by introducing a helper function _is_retryable_commit_error that checks for Aborted exceptions or InvalidArgument exceptions containing the substring 'transaction has expired', and integrating this check into both synchronous and asynchronous transaction commit loops. Comprehensive unit tests are also added. The review feedback recommends making the substring check case-insensitive to ensure robustness against potential casing variations in the backend error message.

Comment on lines +68 to +69
if isinstance(exc, exceptions.InvalidArgument):
return _EXPIRED_TRANSACTION_MESSAGE in str(exc)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To make the check robust against potential casing variations in the backend error message (e.g., "Transaction has expired"), it is safer to perform a case-insensitive substring search by converting the exception string to lowercase.

Suggested change
if isinstance(exc, exceptions.InvalidArgument):
return _EXPIRED_TRANSACTION_MESSAGE in str(exc)
if isinstance(exc, exceptions.InvalidArgument):
return _EXPIRED_TRANSACTION_MESSAGE in str(exc).lower()

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unlike Java/JS, firestore's python transactions do not retry on invalid transaction errors

1 participant