laravel/framework · error · BroadcastException
Ably error
Error message
Ably error: %s
What it means
Thrown by AblyBroadcaster::broadcast() as a BroadcastException when the Ably SDK's channel publish() call raises an AblyException. The message embeds Ably's own error text (sprintf'd) so callers can see the upstream cause. It indicates the message was not delivered to Ably.
Solutions
- Verify ABLY_KEY is a valid, non-expired key with publish capability on the channels you use.
- Check the embedded Ably error message for the specific code (e.g. 40102 invalid key, 40160 capability, 429 rate limit) and act on it.
- Sanitize channel names per Ably rules (alphanumeric, :, -, _; max length).
- For rate limits, batch events or reduce publish frequency.
- Confirm network egress to rest.ably.io / the configured Ably host.
- Wrap broadcast() in a try/catch for BroadcastException to queue a retry or report.
Example fix
// before — broadcast swallows underlying Ably error
broadcast(new OrderShipped($order));
// after — handle BroadcastException and surface Ably's message
try {
broadcast(new OrderShipped($order));
} catch (\Illuminate\Broadcasting\BroadcastException $e) {
Log::error('Ably broadcast failed', ['reason' => $e->getMessage()]);
// optionally retry or push to a queue for later delivery
}
// and fix credentials in .env:
// ABLY_KEY=xxxxx.yyyyy:zzzzz Defensive patterns
Strategy: try-catch
Validate before calling
// PHP — pre-flight Ably key presence before broadcasting
if (config('broadcasting.connections.ably.driver') === 'ably' && empty(config('broadcasting.connections.ably.key'))) {
throw new \RuntimeException('ABLY_KEY is not set; Ably broadcast will fail.');
}
broadcast(new \App\Events\OrderShipped($order)); Type guard
// Heuristic guard for Ably readiness
function ablyCredentialsAreConfigured(): bool {
$cfg = config('broadcasting.connections.ably');
return $cfg && ($cfg['driver'] ?? null) === 'ably' && ! empty($cfg['key']);
} Try / catch
try {
broadcast(new \App\Events\OrderShipped($order));
} catch (\Illuminate\Broadcasting\BroadcastException $e) {
Log::error('Ably broadcast failed', ['reason' => $e->getMessage()]);
// queue for retry or push to a dead-letter
\App\Jobs\RetryBroadcast::dispatch($event)->delay(now()->addSeconds(30));
} Prevention
- Keep a valid ABLY_KEY with publish capability.
- Sanitize channel names per Ably rules.
- Catch BroadcastException and retry/queue instead of surfacing to the user.
- Monitor the embedded Ably error codes (40102, 40160, 429) to act on root cause.
When it happens
Trigger: Broadcasting an event on Ably where publish() fails — invalid/expired Ably key, insufficient channel capabilities, rate limit, network error, malformed channel name, or capacity/protocol errors returned by the Ably REST API.
Common situations: Wrong/rotated ABLY_KEY in .env; channel name with characters Ably rejects; capability rules that forbid publish on the channel; rate limiting under load; egress blocked from the host; Ably service incident.
Related errors
- Failed to create broadcaster for connection
- Broadcast connection
- Driver [ ] is not supported.
- Given channel handler is an unknown type.
- Lost connection and no reconnector available.
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/2f13da29b806a448.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Broadcasting/Broadcasters/AblyBroadcaster.php:134
* Broadcast the given event.
*
* @param array $channels
* @param string $event
* @param array $payload
* @return void
*
* @throws \Illuminate\Broadcasting\BroadcastException
*/
public function broadcast(array $channels, $event, array $payload = [])
{
try {
foreach ($this->formatChannels($channels) as $channel) {
$this->ably->channels->get($channel)->publish(
$this->buildAblyMessage($event, $payload)
);
}
} catch (AblyException $e) {
throw new BroadcastException(
sprintf('Ably error: %s', $e->getMessage())
);
}
}
/**
* Build an Ably message object for broadcasting.
*
* @param string $event
* @param array $payload
* @return \Ably\Models\Message
*/
protected function buildAblyMessage($event, array $payload = [])
{
return tap(new AblyMessage, function ($message) use ($event, $payload) {
$message->name = $event;
$message->data = $payload;
$message->connectionKey = data_get($payload, 'socket');View on GitHub (pinned to e0f6eb3518)