laravel/framework · error · BroadcastException
Pusher error: .
Error message
Pusher error: %s.
What it means
PusherBroadcaster::broadcast wraps the Pusher SDK's trigger() call in a try/catch and re-throws any Pusher\ApiErrorException as a BroadcastException with a descriptive message. The '%s' is the original Pusher SDK message. This is the single chokepoint through which all Pusher transport-level failures surface to application code.
Solutions
- Verify PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_ID, and PUSHER_APP_CLUSTER in .env match the Pusher dashboard values.
- Reduce the broadcast payload size by selecting only needed attributes on models (e.g., $model->only(['id','name'])) and avoid serializing relations.
- Catch \Illuminate\Broadcasting\BroadcastException around broadcast() / event() calls and log/queue a retry for transient Pusher failures.
- Validate channel names against Pusher's allowed pattern (max 200 chars, alphanumeric plus _-=,.@) before broadcasting.
Example fix
// before
broadcast(new OrderShipped($order));
// after
try {
broadcast(new OrderShipped($order));
} catch (\Illuminate\Broadcasting\BroadcastException $e) {
logger()->error('Pusher broadcast failed', ['exception' => $e, 'order_id' => $order->id]);
throw $e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate payload size and channel names before broadcasting
$payload = (new \Illuminate\Broadcasting\BroadcastEvent($event))->payload;
if (strlen(json_encode($payload)) > 10_000) {
throw new \RuntimeException('Pusher payload exceeds 10KB limit');
}
foreach ($channels as $channel) {
if (! preg_match('/^[a-zA-Z0-9_\-=,.@:]{1,200}$/', $channel)) {
throw new \RuntimeException("Invalid Pusher channel name: {$channel}");
}
} Try / catch
use Illuminate\Broadcasting\BroadcastException;
try {
broadcast($event);
} catch (BroadcastException $e) {
if (str_contains($e->getMessage(), 'Pusher error')) {
// log Pusher-specific failure, surface alert
report($e);
return;
}
throw $e;
} Prevention
- Keep Pusher credentials in sync across envs via a secrets manager; rotate on a schedule.
- Cap broadcast payload size at the source — never broadcast full Eloquent models.
- Wrap all broadcast() calls in a project helper that catches BroadcastException and reports.
- Monitor Pusher dashboard error rate; align alert thresholds with broadcast volume.
When it happens
Trigger: Calling event() or broadcast() that targets a Pusher-backed broadcast connection while: Pusher credentials (app key/secret/cluster) are wrong, the channel name violates Pusher naming rules, the payload exceeds Pusher size limits (10KB), the request hits Pusher rate limits, or the network cannot reach the Pusher API.
Common situations: Wrong PUSHER_APP_CLUSTER env value (e.g., 'mt1' vs 'us2'). Mismatched PUSHER_APP_KEY/PUSHER_APP_SECRET between environments. Payload containing large unserialized Eloquent models. Exceeding 100 messages per chunk boundary with malformed channel names. Staging credentials leaking into production.
Related errors
- Failed to create broadcaster for connection
- Redis error: .
- Ably error
- Broadcast connection
- Class based channel must define a "join" method.
AI-assisted analysis of laravel/framework@e0f6eb3518 (2026-08-11).
Data as JSON: /api/errors/1759edaab0940481.
Report an issue: GitHub.
Appendix: source
Thrown at src/Illuminate/Broadcasting/Broadcasters/PusherBroadcaster.php:171
* @param array $payload
* @return void
*
* @throws \Illuminate\Broadcasting\BroadcastException
*/
public function broadcast(array $channels, $event, array $payload = [])
{
$socket = Arr::pull($payload, 'socket');
$parameters = $socket !== null ? ['socket_id' => $socket] : [];
$channels = new Collection($this->formatChannels($channels));
try {
$channels->chunk(100)->each(function ($channels) use ($event, $payload, $parameters) {
$this->pusher->trigger($channels->toArray(), $event, $payload, $parameters);
});
} catch (ApiErrorException $e) {
throw new BroadcastException(
sprintf('Pusher error: %s.', $e->getMessage())
);
}
}
/**
* Get the Pusher SDK instance.
*
* @return \Pusher\Pusher
*/
public function getPusher()
{
return $this->pusher;
}
/**
* Set the Pusher SDK instance.
*View on GitHub (pinned to e0f6eb3518)