Environment
- OS: Linux / macOS
- Python: 3.10+
- google-cloud-spanner: 3.55.0 (also confirmed on
main branch as of 2026-02-11)
Summary
PingingPool.bind() and FixedSizePool.bind() do not include user-assigned labels in the BatchCreateSessionsRequest session_template. This means sessions created eagerly during bind() never receive the labels passed to the pool constructor, even though the labels parameter is accepted and documented.
Expected behavior
Sessions created during PingingPool.bind() should carry the labels passed via PingingPool(labels={"key": "value"}), matching the behavior of _new_session() which correctly passes labels.
Actual behavior
The session_template in bind() only includes creator_role:
# pool.py - PingingPool.bind()
request = BatchCreateSessionsRequest(
database=database.name,
session_count=self.size,
session_template=Session(creator_role=self.database_role), # labels missing
)
While _new_session() correctly passes labels:
# pool.py - AbstractSessionPool._new_session()
return self._database.session(
labels=self.labels, database_role=self.database_role
)
As a result, only sessions lazily created via _new_session() (e.g., to replace expired sessions) receive labels. The initial batch of sessions created in bind() does not.
Steps to reproduce
from google.cloud import spanner
from google.cloud.spanner_v1 import SpannerClient
pool = spanner.PingingPool(size=2, default_timeout=10, labels={"env": "test"})
client = spanner.Client(project="my-project")
instance = client.instance("my-instance")
db = instance.database("my-database", pool=pool)
# Check sessions via Admin API
admin_client = SpannerClient()
db_path = f"projects/my-project/instances/my-instance/databases/my-database"
for session in admin_client.list_sessions(database=db_path):
print(dict(session.labels))
# Prints: {} (empty) -- expected: {"env": "test"}
pool.clear()
Suggested fix
Include self._labels (or self.labels) in the session_template passed to BatchCreateSessionsRequest in both PingingPool.bind() and FixedSizePool.bind():
request = BatchCreateSessionsRequest(
database=database.name,
session_count=self.size,
session_template=Session(
creator_role=self.database_role,
labels=self._labels, # <-- add this
),
)
The Spanner API's BatchCreateSessionsRequest.session_template already supports labels — we confirmed that passing labels in the template correctly applies them to all created sessions.
Environment
mainbranch as of 2026-02-11)Summary
PingingPool.bind()andFixedSizePool.bind()do not include user-assignedlabelsin theBatchCreateSessionsRequestsession_template. This means sessions created eagerly duringbind()never receive the labels passed to the pool constructor, even though thelabelsparameter is accepted and documented.Expected behavior
Sessions created during
PingingPool.bind()should carry the labels passed viaPingingPool(labels={"key": "value"}), matching the behavior of_new_session()which correctly passes labels.Actual behavior
The
session_templateinbind()only includescreator_role:While
_new_session()correctly passes labels:As a result, only sessions lazily created via
_new_session()(e.g., to replace expired sessions) receive labels. The initial batch of sessions created inbind()does not.Steps to reproduce
Suggested fix
Include
self._labels(orself.labels) in thesession_templatepassed toBatchCreateSessionsRequestin bothPingingPool.bind()andFixedSizePool.bind():The Spanner API's
BatchCreateSessionsRequest.session_templatealready supportslabels— we confirmed that passing labels in the template correctly applies them to all created sessions.