Q:

What is the logic for acknowledging then rejecting an AMQP Message?

I've been playing around with the RabbitMQ client for AMQP and I noticed that ack and reject both just take a delivery tag. What happens if you ack then reject the same delivery tag? RabbitMQ doesn't error out, but I'm wondering if this should throw an error saying that the delivery tag has already been "claimed".
Does the AMQP specification have anything to say about this?

A:

Short answer
basic.ack, basic.nack, basic.reject and some other methods are idempotent, so invoking them with the same arguments multiple time make effect only once.
Long answer
There are AMQP specification on AMQP protocol on RabbitMQ which you probably saw, but I will make accent on basic.ack  which according to docs

Acknowledge one or more messages ... acknowledgement can be for a single message or a set of messages up to and including a specific message 

Same can be found in spec, paragraph 1.8.3.13.

This method acknowledges one or more messages delivered via the Deliver or Get­Ok methods. The client can ask to confirm a single message or a set of messages up to and including a specific message.

So if you send basic.ack with non-existent delivery tag nothing will happen, while there is no such message marked as pending ack'ing/nack'ing in queue, nothing will be ack'ed.
basic.reject works in a similar way, but only on a specific message.
The important moment about AMQP protocol that it has asynchronous designed, so almost everything is a subject to race conditions. RabbitMQ doesn't screaming on everything while it designed to be high-performance and reliable system, not loud and heavy.
I can suggest you this use case: for example, you consume messages in main thread and pass it to child threads, one or more, so it may happen that one child done processing and the other finish it slightly later. Sure, it is an example of bad designed architecture, but RabbitMQ doesn't take care about badly-designed producers and consumers, in general, and still work.

