-
Notifications
You must be signed in to change notification settings - Fork 192
Description
Description
When attempting to publish a message to an exchange that the user does not have permission to write to, the channel raises an AccessRefused error (403) as expected. However, after this error occurs, subsequent attempts to publish on the same channel hang indefinitely instead of returning an error or otherwise recovering gracefully.
According to the AMQP 0-9-1 protocol, when a 403 (“AccessRefused”) is triggered, the broker typically sends a channel.close method. The client library should then close that channel and raise an exception, allowing the user to handle the error and open a new channel if needed. In some cases, RabbitMQ may also set certain flags (e.g., connection.blocked frames or channel-blocked signals) depending on how the broker is configured and how the error is propagated.
In this scenario, it appears that py-amqp either does not fully close or reset the channel after receiving the AccessRefused, leaving the channel in a “blocked” or “bad” state. Any subsequent publish calls on this channel remain stuck because the broker has effectively closed or blocked the channel from further use.
Below is a minimal reproducible example demonstrating the issue:
from amqp import Connection, Message
# Establish connection and open channel
con = Connection(host='rabbitmq', userid='example-user', password='example-user', virtual_host='/')
con.connect()
chan = con.channel()
# 1) This line triggers an AccessRefused exception because the user lacks permission:
# AccessRefused: Basic.publish: (403) ACCESS_REFUSED - write access to exchange 'system-configuration'
# in vhost '/' refused for user 'example-user'
chan.basic_publish_confirm(Message(b''), 'system-configuration', 'a.config.c')
# 2) After the above error occurs, attempting to reuse the same channel hangs forever:
chan.basic_publish_confirm(Message(b''), 'example-exchange', 'a.config.c')Steps to Reproduce
- Set up a RabbitMQ user (
example-user) with permission to publish on some exchanges, but not onsystem-configuration. - Run the above code.
- Observe that the first publish call fails with
AccessRefused (403)as expected. - Note that the second publish call never returns, causing the application to hang indefinitely.
Expected Behavior
- After encountering
AccessRefused, the channel should close or become invalid, and the library should raise a clear exception if further operations are attempted. - Future calls on the same channel should either fail fast with an error indicating the channel is closed, or allow the application to recover by reopening or recreating the channel.
Actual Behavior
- The channel appears to enter a “blocked” or otherwise bad state after the first failed publish.
- Subsequent calls to
basic_publish_confirmwith valid exchanges hang and never return. - The library does not appear to handle the channel close gracefully.
Environment
- py-amqp version: 5.3.1
- Python version: 3.13
- RabbitMQ version: 3.13
- OS: Debian 12.5-slim (based on
python:3.13-slimDocker image)
Additional Notes
- This behavior suggests that py-amqp is not handling the server’s
channel.close(or related block signals) properly in response to the403error. - A workaround is to catch the
AccessRefusedexception explicitly, discard the failed channel, and open a new one for subsequent operations. However, the more intuitive behavior would be for py-amqp to automatically detect the channel is closed and raise an error on further usage, rather than hanging. - Please let me know if any additional logs or information would help diagnose this issue further.