A poison message should reach the failure transport after a bounded number of attempts. If every delivery is logged as retry number one, the decode path is probably losing the redelivery stamps that carry the attempt count.
Last updated: November 5, 2026.
<?php
use SymfonyComponentMessengerEnvelope;
use SymfonyComponentMessengerExceptionMessageDecodingFailedException;
use SymfonyComponentMessengerTransportSerializationSerializerInterface;
final class JsonMessageSerializer implements SerializerInterface
{
public function decode(array $encoded): Envelope|MessageDecodingFailedException
{
try {
return $this->decodeEnvelope($encoded);
} catch (Throwable $error) {
return MessageDecodingFailedException::wrap(
$encoded,
'Message payload could not be decoded',
0,
$error,
);
}
}
}For Symfony 8.1 custom serializers, return the wrapped decoding failure instead of throwing it. The transport can then retain the available headers and route the failure through its retry policy.
Configure a bounded failure path
The current Symfony Messenger guide says undecodable messages enter the normal retry and failure-transport pipeline. It also requires the failure transport to use the same serializer as the source transport so a repaired message can be decoded when retried later.
Set a finite max_retries, a delay with jitter, and a named failure transport. A recent Symfony report shows how a custom serializer that throws during decode() can lose retry stamps and repeatedly appear as its first retry. Check the exact Symfony patch version and update when the project publishes a verified fix.
Test the poison-message case
Put one intentionally malformed envelope on a disposable queue. Run a worker with verbose logs and assert that retry numbers advance, the source queue eventually releases the message, and exactly one record arrives in the failure transport. Monitor both queue depth and the age of the oldest message; a failure queue staying empty is not evidence of health.
Do not log the complete bad payload when it may contain credentials or personal data. Log a message ID, transport, serializer version, exception class, and a bounded sanitized reason. Keep the original envelope available under the queue system’s access controls for diagnosis.
If an error is permanently unrecoverable after successful decoding, throw the documented unrecoverable handling exception rather than retrying it. Continue with queue retry design, reliable queue workers, and durable queue dispatch.