One of the lessons I've learned the hard way with complex messaging systems is that you need to use a some sort of common 'context' header that is attached to any message. One of the things that is helpful to add is a breadcrumb trail. Essentially, to start, when you have a message generated by the receipt of another, you record the source in the context. But take it one step further, you should also attach the history from the source event. As messages bounce around the pachinko machine, you now have a history of the path that was taken.
Once you have that, you can now do a simple check for cycles (this works for any graph-type situation by the way): check the history and if the current 'location' is already in the history, you have a cycle and you can route the message to a poison-message handling subsystem.
Of course, if you've designed thing to purposely loop through the same topics/queues (yes, I've seen this,) you will have a much harder problem to solve. I would avoid such designs anyway because they are problematic in general.
The big challenge is making sure this hand-off happens reliably. The best way to ensure this is to bake it into your libraries and APIs for message consumption/production.