Repository navigation
[spanner] RequestOptions.transaction_tag is unexpectedly mutated to '' when passed to snapshot.read() #17902
Description
Determine this is the right repository
- I determined this is the correct repository in which to report this bug.
Summary of the issue
When passing a RequestOptions instance with a transaction_tag to snapshot.read(), the transaction_tag attribute of the original object is unexpectedly mutated to '' (empty string).
API client name and version
google-cloud-spanner==3.69.0
Reproduction steps: code
from google.cloud import spanner
from google.cloud.spanner_v1.types import RequestOptions
spanner_client = spanner.Client()
instance = spanner_client.instance("your-instance-id")
database = instance.database("your-database-id")
request_opts = RequestOptions(transaction_tag="tran1")
print("Before read:", request_opts.transaction_tag)
with database.snapshot() as snapshot:
snapshot.read(
table="Singers",
columns=("SingerId", "FirstName"),
keyset=spanner.KeySet(all_=True),
request_options=request_opts,
)
print("After read:", request_opts.transaction_tag)
Reproduction steps: supporting files
No response
Reproduction steps: actual results
Before read: tran1
After read:
Reproduction steps: expected results
Before read: tran1
After read: tran1
OS & version + platform
Windows 11
Python environment
Python 3.14.6
Python dependencies
pip list
Package Version
certifi 2026.7.22
cffi 2.1.0
charset-normalizer 3.4.9
cryptography 49.0.0
google-api-core 2.33.0
google-auth 2.56.2
google-cloud-core 2.6.0
google-cloud-monitoring 2.31.0
google-cloud-spanner 3.69.0
google-cloud-storage 3.13.0
google-crc32c 1.8.0
google-resumable-media 2.10.0
googleapis-common-protos 1.75.0
grpc-google-iam-v1 0.14.4
grpc-interceptor 0.15.4
grpcio 1.82.1
grpcio-status 1.82.1
idna 3.18
mmh3 5.2.1
opentelemetry-api 1.44.0
opentelemetry-resourcedetector-gcp 1.12.0a0
opentelemetry-sdk 1.44.0
opentelemetry-semantic-conventions 0.65b0
pip 26.1.2
proto-plus 1.28.2
protobuf 7.35.1
pyasn1 0.6.4
pyasn1_modules 0.4.2
pycparser 3.0
requests 2.34.2
sqlparse 0.5.5
typing_extensions 4.16.0
urllib3 2.7.0
Additional context
Passing an object as an argument should not destructively mutate the caller's input object.
Activity
adityaanikam commentedon Jul 29, 2026
I'd like to work on this. Not something I've traced through the Spanner client internals yet, but the repro is unambiguous: passing
request_optsintosnapshot.read()and readingrequest_opts.transaction_tagafterward shows it went from"tran1"to"". That points toread()(or something it calls into) mutating the caller'sRequestOptionsobject in place most likely clearing/repurposing a field on the same instance rather than copying it before use internally. I'll trace the read path to find exactly wheretransaction_taggets touched and confirm whether the fix is "don't mutate the input" (copy before use) or "restore the field before returning" the former is the more correct fix if nothing legitimately needs the original value cleared for the call to succeed.