Publisher confirms, or the message was never sent

basic_publish returns as soon as the message is written to the socket. The broker may not have accepted it, may not have routed it anywhere, and may have been down — none of which produces an error at the call site.

$channel->confirm_select();

$channel->set_nack_handler(function ($message) {
    Log::error('broker rejected message', ['body' => $message->body]);
});

$channel->basic_publish($message, 'orders', 'order.placed');
$channel->wait_for_pending_acks(5);

Confirms are per channel and cost a round trip, which is the reason they are off by default. The other silent failure is routing: a message published to an exchange with no matching binding is discarded without complaint, and the mandatory flag with a return listener is what surfaces it. Both together are the difference between publishing and hoping.