Room widgets never render — matrix-widget-api 1.17.0 isValidUrl is broken #15

Closed
opened 2026-09-12 01:50:51 -04:00 by jared · 0 comments
Owner

Severity: high · Type: bug · Confidence: high

Location: src/app/features/room/widgets/useRoomWidgets.ts:13-21, src/app/features/room/widgets/WidgetsPanel.tsx:51, node_modules/matrix-widget-api/src/models/validation/url.ts:17-31

Problem

useRoomWidgets delegates entirely to WidgetParser.parseWidgetsFromRoomState. That helper
calls isValidUrl, which compares new URL(val).protocol against the strings "http" / "https"
but URL.protocol always carries a trailing colon ("https:"), so the comparison never matches and
the function returns false for every URL. processEstimatedWidget therefore returns null for
every widget and the parser always yields []. The whole MSC1236 widgets feature (listed as shipped
in LOTUS_TODO.md) is dead: the panel permanently shows its empty state, including for widgets the
user just added.

How to trigger

node -e "const {WidgetParser}=require('matrix-widget-api'); console.log(WidgetParser.parseWidgetsFromRoomState([{type:'im.vector.modular.widgets',state_key:'w1',sender:'@a:b',content:{id:'w1',type:'custom',url:'https://example.com/w',name:'W',creatorUserId:'@a:b'}}]))" prints []. In the app: add any widget to a room, reopen the Widgets panel — it is empty.

Suggested fix

stop relying on WidgetParser — build Widget objects in useRoomWidgets from the
raw state events with a local scheme check (url.protocol === 'https:', plus the existing
isWidgetUrlSafe origin check) — or pin/patch a fixed matrix-widget-api.


Filed from the September 2026 client audit (branch lotus @ 4bea4895).

**Severity:** high · **Type:** bug · **Confidence:** high **Location:** `src/app/features/room/widgets/useRoomWidgets.ts:13-21`, `src/app/features/room/widgets/WidgetsPanel.tsx:51`, `node_modules/matrix-widget-api/src/models/validation/url.ts:17-31` ### Problem `useRoomWidgets` delegates entirely to `WidgetParser.parseWidgetsFromRoomState`. That helper calls `isValidUrl`, which compares `new URL(val).protocol` against the strings `"http"` / `"https"` — but `URL.protocol` always carries a trailing colon (`"https:"`), so the comparison never matches and the function returns `false` for **every** URL. `processEstimatedWidget` therefore returns `null` for every widget and the parser always yields `[]`. The whole MSC1236 widgets feature (listed as shipped in `LOTUS_TODO.md`) is dead: the panel permanently shows its empty state, including for widgets the user just added. ### How to trigger `node -e "const {WidgetParser}=require('matrix-widget-api'); console.log(WidgetParser.parseWidgetsFromRoomState([{type:'im.vector.modular.widgets',state_key:'w1',sender:'@a:b',content:{id:'w1',type:'custom',url:'https://example.com/w',name:'W',creatorUserId:'@a:b'}}]))"` prints `[]`. In the app: add any widget to a room, reopen the Widgets panel — it is empty. ### Suggested fix stop relying on `WidgetParser` — build `Widget` objects in `useRoomWidgets` from the raw state events with a local scheme check (`url.protocol === 'https:'`, plus the existing `isWidgetUrlSafe` origin check) — or pin/patch a fixed `matrix-widget-api`. --- _Filed from the September 2026 client audit (branch `lotus` @ 4bea4895)._
jared added this to the Audit 2026-09 · High milestone 2026-09-12 01:50:51 -04:00
jared added the bugpriority: higharea: messaging labels 2026-09-12 01:50:51 -04:00
jared self-assigned this 2026-09-12 01:50:51 -04:00
jared closed this issue 2026-09-12 19:46:16 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2026-10-14
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#15