Realtime: WarnSendingBroadcastMessage when broadcasting from the database
If you broadcast from the database with realtime.send or realtime.send_binary, you may see this in your Postgres logs:
1WARNING: WarnSendingBroadcastMessage: <reason>It means the function could not insert the row into realtime.messages, so that message was not broadcast. This shows up in an edge case where the message would not have reached anyone anyway. This guide explains when that is the case and when the warning points to a real problem.
Why the dropped message would not have been delivered#
Realtime broadcasts database changes by streaming the realtime.messages table through a replication slot. That slot only starts once a client connects over WebSocket and the connection process begins streaming. The slot is temporary and does not replay history, so it only delivers messages inserted after a client connected.
So if you call realtime.send while nobody is connected, the message would not reach anyone even if the insert succeeded. No connection means no listener. Dropping it is the same outcome.
This is why the log line is a warning and not an error.
What usually triggers it#
The most common cause is a missing daily partition on realtime.messages. The table is partitioned by day, and realtime.send or realtime.send_binary does not create partitions itself. If no partition exists for the current day, the insert fails with a message like no partition of relation "messages" found for row, and you get the WarnSendingBroadcastMessage warning.
Partitions are created in three occasions:
| Where | When it runs |
|---|---|
| A client connects over WebSocket | The first time a client joins a channel for the project, after database migrations run |
| The tenant health check endpoint | When the health endpoint is called and the project either has an active database connection or has connected clients. Opening the Realtime section of your project dashboard calls this endpoint |
| The scheduled janitor | Periodically (roughly every 4 hours), when it deletes old messages and recreates the partition window. It only runs for projects that have had a connection established at least once |
Each of these creates a rolling window of partitions: yesterday, today, and the next three days.
What's not included
Calling realtime.send / realtime.send_binary, the broadcast REST endpoint, and subscribe or replication operations do not create partitions. So a project that has never had a WebSocket client connect, and whose health check and janitor have not yet run for the day, has no partition to insert into. Broadcasting from the database before that point produces the warning.
How to avoid it#
- Connect a client before broadcasting from the database. A live WebSocket connection both creates the partitions and starts the consumer that actually receives the message.
- If you broadcast from the database on a schedule, make sure at least one subscriber is connected when you send. Otherwise the messages have no destination.
When it is a real problem#
If you see this warning repeatedly while clients are connected and partitions exist, the insert is failing for another reason. The actual cause is in the <reason> part of the log line (the underlying SQLERRM). Check your Postgres logs for that text rather than assuming it is a missing partition. Common examples are a constraint violation or a permissions issue on realtime.messages.