Related issues
Same root cause as #35618 and #36334 (internal _handler reset to None),
but a different trigger: those reproduce under concurrent sends and were
closed not_planned with an asyncio.Lock() workaround. This report is a
single-threaded, non-concurrent reproduction driven by Azure's ~10-minute
idle timeout — the lock workaround does not apply.
Describe the bug
A long-lived (singleton) async ServiceBusSender that is reused across sends
works fine until the connection sits idle past Azure's ~10-minute idle timeout.
The next send_messages() raises:
AttributeError: 'NoneType' object has no attribute 'client_ready_async'
Expected: a documented, catchable ServiceBusConnectionError (or transparent
implicit reconnect), so callers can distinguish "stale link, safe to recreate
and retry" from a genuine error (auth/quota/payload).
Because the leaked exception is a bare AttributeError, callers cannot reliably
tell it apart from an ordinary programming bug without string-matching on the
internal attribute name client_ready_async, which is fragile across releases.
Steps to reproduce
- Create an async
ServiceBusClient, then one ServiceBusSender, and keep both.
await sender.send_messages(...) once — succeeds.
- Leave the sender idle for > 10 minutes (Azure idle timeout drops the AMQP link).
await sender.send_messages(...) again.
Result: AttributeError: 'NoneType' object has no attribute 'client_ready_async'
rather than a ServiceBusConnectionError.
Minimal sketch:
import asyncio
from azure.servicebus.aio import ServiceBusClient
from azure.servicebus import ServiceBusMessage
async def main():
client = ServiceBusClient.from_connection_string(CONN_STR)
sender = client.get_queue_sender(QUEUE)
await sender.send_messages(ServiceBusMessage("first")) # ok
await asyncio.sleep(11 * 60) # exceed idle timeout
await sender.send_messages(ServiceBusMessage("second")) # AttributeError
asyncio.run(main())
Expected behavior
The idle-dropped link should surface as ServiceBusConnectionError (the SDK's
documented connection-loss exception), or the sender should reconnect implicitly.
Either way, no internal AttributeError should escape.
Environment
azure-servicebus: 7.14.3 (latest stable)
azure-core: 1.38.2
Python: 3.11.14
OS: Windows 11 (also observed in Linux containers)
Transport: async (azure.servicebus.aio), pure-Python AMQP
Impact / current workaround
We run one persistent sender per worker and must detect this failure to recreate
the sender and retry. Since no typed exception is raised, we string-match:
isinstance(exc, AttributeError) and "client_ready_async" in str(exc)
This is brittle — it depends on an internal attribute name. A typed exception
(or implicit reconnect) would let us delete the string match. Please consider
fixing the idle-timeout path specifically, independently of the concurrency
scenarios in
Azure/azure-sdk-for-python#35618 /
Azure/azure-sdk-for-python#36334.
Related issues
Same root cause as #35618 and #36334 (internal
_handlerreset toNone),but a different trigger: those reproduce under concurrent sends and were
closed
not_plannedwith anasyncio.Lock()workaround. This report is asingle-threaded, non-concurrent reproduction driven by Azure's ~10-minute
idle timeout — the lock workaround does not apply.
Describe the bug
A long-lived (singleton) async
ServiceBusSenderthat is reused across sendsworks fine until the connection sits idle past Azure's ~10-minute idle timeout.
The next
send_messages()raises:Expected: a documented, catchable
ServiceBusConnectionError(or transparentimplicit reconnect), so callers can distinguish "stale link, safe to recreate
and retry" from a genuine error (auth/quota/payload).
Because the leaked exception is a bare
AttributeError, callers cannot reliablytell it apart from an ordinary programming bug without string-matching on the
internal attribute name
client_ready_async, which is fragile across releases.Steps to reproduce
ServiceBusClient, then oneServiceBusSender, and keep both.await sender.send_messages(...)once — succeeds.await sender.send_messages(...)again.Result:
AttributeError: 'NoneType' object has no attribute 'client_ready_async'rather than a
ServiceBusConnectionError.Minimal sketch:
Expected behavior
The idle-dropped link should surface as ServiceBusConnectionError (the SDK's
documented connection-loss exception), or the sender should reconnect implicitly.
Either way, no internal AttributeError should escape.
Environment
azure-servicebus: 7.14.3 (latest stable)
azure-core: 1.38.2
Python: 3.11.14
OS: Windows 11 (also observed in Linux containers)
Transport: async (azure.servicebus.aio), pure-Python AMQP
Impact / current workaround
We run one persistent sender per worker and must detect this failure to recreate
the sender and retry. Since no typed exception is raised, we string-match:
isinstance(exc, AttributeError) and "client_ready_async" in str(exc)
This is brittle — it depends on an internal attribute name. A typed exception
(or implicit reconnect) would let us delete the string match. Please consider
fixing the idle-timeout path specifically, independently of the concurrency
scenarios in
Azure/azure-sdk-for-python#35618 /
Azure/azure-sdk-for-python#36334.