The bus is the part of Odoo most engineers never think about until it breaks: the channel that pushes live notifications (new messages, presence, UI refreshes) from server to browser without a page reload. In Odoo 19 it finished a transition that had been underway for several versions, and the cleanup removed things custom code may have been relying on.
The legacy presence endpoint is gone
The /websocket/update_bus_presence route no longer exists. Code that posted to it to announce user presence, usually older custom widgets or integrations, will get a 404. Presence is now handled inside the WebSocket subscription flow, not as a separate HTTP call.
Route types changed: json became jsonrpc
The bus controller's JSON routes (/websocket/peek_notifications, /websocket/on_closed) moved from type='json' to type='jsonrpc'. If you wrote a controller that _inherits one of these or registered a route alongside them with the old type, the declarations no longer match. This is a small change that produces a confusing failure, because the route still exists. It just no longer behaves the way an inheriting override expects.
Presence overrides need rewriting
v18's ir.websocket exposed a cluster of presence methods: _get_missed_presences_identity_domains(), _get_missed_presences_bus_target(), and _build_presence_channel_list(). v19 collapses all of that behind a single hook, _after_subscribe_data(data), called once after a subscription is established. Custom code that overrode the old granular methods to inject extra channels or presence logic has nothing to attach to anymore; that logic moves into the new hook.
Channel subscription now includes implied groups
Group-based bus channels are built from a different field. v18 used self.env.user.groups_id; v19 uses self.env.user.all_group_ids, which includes implied groups. If your module pushes notifications to a group channel, v19 will deliver them to more users than v18 did: users who hold the group by implication rather than direct assignment. Usually that is correct. Occasionally it is a surprise. Either way, know it changed.
The reliability angle: PoolError and the connection budget
v19's bus module added an import that tells you where Odoo's own thinking went: from psycopg2.pool import PoolError. The WebSocket architecture holds long-lived connections, and each one competes for the same PostgreSQL connection pool as everything else: interactive requests, scheduled jobs, report generation.
This is the failure mode to watch on a busy deployment. A flood of WebSocket clients, plus a cluster of crons firing together, can exhaust the pool. The symptom is not "the bus is slow". It is intermittent PoolError exceptions in places that look unrelated. The fix is budgeting: size the pool against the real concurrent connection count, including bus connections, and stagger heavy crons so they don't all contend at once. If JSON serialization shows up in bus profiling, v19 also supports the optional orjson library as a drop-in faster encoder.
Migration checklist
- Remove any client or server code that calls
/websocket/update_bus_presence. - Update bus-related route overrides from
type='json'totype='jsonrpc'. - Replace
_get_missed_presences_*overrides with a single_after_subscribe_dataoverride. - Re-check group-channel notifications now that subscription uses
all_group_ids. - Update references to the bus model class from
ImBustoBusBus(the model namebus.busis unchanged). - Budget your PostgreSQL connection pool against bus connections plus cron concurrency.
The bus rewards being ignored, right up until an upgrade. v19 is a good moment to look at it deliberately, because it is the version that stopped tolerating the old way of talking to it.