Summary
When a merchant clicks an app nav item in the admin sidebar (<ui-nav-menu> / NavMenu), App Bridge looks for the matching anchor by calling new URL(href) on every a, s-link, s-button and s-clickable in the app document, not only the nav menu’s children. If any of them has an href that new URL() rejects, the call throws. The navigation is then dropped: the admin URL changes, but the app never navigates. Nothing visible tells the merchant or the developer why.
Environment
https://cdn.shopify.com/shopifycloud/app-bridge.js(unversioned CDN build, fetched 2026-10-22)- Embedded app, React Router
BrowserRouter, nav declared withNavMenufrom@shopify/app-bridge-react(<Link to="/sections">children) - Chrome, Shopify admin web
Steps to reproduce
-
In an embedded app with a
NavMenu, render anywhere in the app document (outside the nav menu):<a href="http://查看:https://example.com/">link</a>The host contains a full-width colon (U+FF1A). Chat widgets produce exactly this when they auto-link a URL glued to CJK text.
-
In the admin sidebar, click a nav item other than the current page.
Expected
The app navigates to the clicked route. An unrelated invalid anchor should be skipped.
Actual
-
The admin URL changes (e.g.
/apps/<app>/sections), but the app stays on the previous screen. -
The console shows:
Uncaught (in promise) TypeError: Failed to construct 'URL': Invalid URL at on (app-bridge.js:1) at (anonymous) (app-bridge.js:1) at an (app-bridge.js:1) at r (app-bridge.js:1) at dispatchEvent (app-bridge.js:1)
Analysis (names are from the minified build, so they may change)
rn()builds a selector that, besidesui-nav-menu > aands-app-nav > a, also includes plaina,s-link,s-buttonands-clickable, then callsdocument.querySelectorAllon it. That returns every anchor in the document.an()runsrn().filter(el => ln(target, on(el.getAttribute('href')))).on()callsnew URL(href, location.href). Forshopify:,app:andextension:URLs it also re-parsesnew URL(protocol + '/' + ...). Neither call is wrapped in a try/catch, so one bad href rejects the navigate handler.
Suggested fix
- Skip anchors whose href fails to parse, for example with a try/catch inside the
filtercallback (or aroundon()). - And/or scope the lookup to the nav menu’s own children (
ui-nav-menu > a,s-app-nav > a) before falling back to the whole document.
Impact
- Real merchant reports: sidebar navigation “does nothing” in our app, only for stores whose support chat history contains such a message.
- Content the app does not control (third-party widgets, merchant-entered text) can break core admin navigation.
- We have shipped an app-side workaround that repairs invalid hrefs inside our chat widget. The general case can only be fixed in App Bridge.