Skip to content

eagerPreload: anchorUrl throws 'Invalid URL' on anchors not yet adopted into the page #704

Closed

Description

@lovrozagar

Versions: @solidjs/router 2.0.0-next.42, @solidjs/web 2.0.0-rc.18, Chromium.

What happens

With preloadLinks: eagerPreload({ all: true }), the idle flush can throw:

TypeError: Failed to construct 'URL': Invalid URL
    at anchorUrl (dist/data/events.js:55)
    at ambientPreload (dist/preload.js:49)

eagerPreload claims anchors when they are created (claimAnchors, dist/preload.js:11) and preloads them at idle (:165). anchorUrl does new URL(href) with no base (dist/data/events.js:55).

Solid clones compiled nodes from a <template> (@solidjs/web dist/web.js:430-437). A clone belongs to the template's inert document, whose base is about:blank, so a.href is the raw attribute (e.g. /about) until the node is adopted into the page. If the idle flush runs before that, for example while a transition holds the new tree off the page, new URL("/about") throws, uncaught.

Browser check:

const t = document.createElement("template")
t.innerHTML = '<a href="/about">about</a>'
const a = t.content.firstChild.cloneNode(true)
a.href          // "/about": not resolved
new URL(a.href) // TypeError: Failed to construct 'URL': Invalid URL

Repro

  1. createRouter({ preloadLinks: eagerPreload({ all: true }), ... }).
  2. A route whose component renders <a href="/about"> next to an async memo that resolves after 1.5 s.
  3. Load another page, wait for load, then navigate to that route client-side.
  4. The idle flush runs while the new tree is still off the page, and the TypeError above is thrown.

Expected

An anchor that isn't connected is skipped (or stays queued) and is preloaded once it is in the page.

Suggested fix

In the flush, skip anchors with !a.isConnected (or keep them queued). In anchorUrl, resolve HTML anchors against document.baseURI, as is already done for SVG anchors.

Activity

  1. ryansolid commented on Oct 28, 2026

    @ryansolid
    Member

    Fixed on next by #706: anchors now resolve against document.baseURI, so a template clone that isn't adopted yet no longer throws and preloads its route. It ships in 2.0.0-next.43.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions