php-amqplib/php-amqplib · critical · AMQPConnectionClosedException
$code
$code
Error message
socket_strerror($code)
What it means
In SocketIO::write(), when socket_write() raises an ErrorException, the code maps the errno: connection-fatal codes (EPIPE, ENETDOWN, ENETUNREACH, ENETRESET, ECONNABORTED, ECONNRESET, ECONNREFUSED, ETIMEDOUT) close the socket and throw AMQPConnectionClosedException whose message is socket_strerror($code) — the raw OS error text (e.g. 'Broken pipe'). This is the transport-level signal that the TCP connection is gone.
Solutions
- Catch AMQPConnectionClosedException and reconnect ($connection->reconnect(), re-open channels) before retrying the publish.
- Enable client heartbeats and keepalive so dead TCP connections are detected and re-established proactively.
- Check the broker is reachable and its advertised host/port/firewall rules allow sustained connections.
- Use publisher confirms / message persistence so messages lost during connection drops can be resent.
Example fix
// before
$channel->basic_publish($msg, 'ex');
// after
try {
$channel->basic_publish($msg, 'ex');
} catch (PhpAmqpLib\Exception\AMQPConnectionClosedException $e) {
$connection->reconnect();
$channel = $connection->channel();
$channel->basic_publish($msg, 'ex');
} Defensive patterns
Strategy: retry
Validate before calling
if (!$connection->isConnected()) { $connection->reconnect(); $channel = $connection->channel(); } Try / catch
try {
$channel->basic_publish($msg, 'ex');
} catch (\PhpAmqpLib\Exception\AMQPConnectionClosedException $e) {
$connection->reconnect();
$channel = $connection->channel();
$channel->basic_publish($msg, 'ex');
} Prevention
- Set client heartbeat (e.g. 30s) and TCP keepalive
- Use publisher confirms for at-least-once delivery
- Monitor broker availability and restarts
- Avoid holding connections open across deployments without health checks
When it happens
Trigger: Publishing or sending any frame when the peer has reset or closed the TCP connection: broker restart, ECONNREFUSED after broker shutdown, broken pipe after broker closed the socket, ETIMEDOUT on a dead network path.
Common situations: Long-running RabbitMQ consumer losing the broker (restart, failover, HA promotion); network partition or VPN drop; broker closing idle connections because heartbeats are disabled or too large; Docker/k8s restarting the RabbitMQ container under a producer.
Related errors
- Broken pipe or closed connection
- $code
- Error reading data. Received
- Error sending data. Connection timed out.
- Error sending data. Last SocketError
AI-assisted analysis of php-amqplib/php-amqplib@381b6f7c60 (2026-09-20).
Data as JSON: /api/errors/70987d40b0125c37.
Report an issue: GitHub.
Appendix: source
Thrown at PhpAmqpLib/Wire/IO/SocketIO.php:214
$buffer = mb_substr($data, $written, self::BUFFER_SIZE, 'ASCII');
}
$result = socket_write($this->sock, $buffer);
}
$this->throwOnError();
} catch (\ErrorException $e) {
$code = socket_last_error($this->sock);
$constants = SocketConstants::getInstance();
switch ($code) {
case $constants->SOCKET_EPIPE:
case $constants->SOCKET_ENETDOWN:
case $constants->SOCKET_ENETUNREACH:
case $constants->SOCKET_ENETRESET:
case $constants->SOCKET_ECONNABORTED:
case $constants->SOCKET_ECONNRESET:
case $constants->SOCKET_ECONNREFUSED:
case $constants->SOCKET_ETIMEDOUT:
$this->close();
throw new AMQPConnectionClosedException(socket_strerror($code), $code, $e);
default:
throw new AMQPIOException(sprintf(
'Error sending data. Last SocketError: %s',
socket_strerror($code)
), $code, $e);
}
} finally {
$this->restoreErrorHandler();
}
if ($result === false) {
throw new AMQPIOException(sprintf(
'Error sending data. Last SocketError: %s',
socket_strerror(socket_last_error($this->sock))
));
}
$now = microtime(true);View on GitHub (pinned to 381b6f7c60)