<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/page.cgi?id=bugzilla.dtd">

<bugzilla version="5.0.4.1"
          urlbase="https://bugs.webkit.org/"
          
          maintainer="admin@webkit.org"
>

    <bug>
          <bug_id>314976</bug_id>
          
          <creation_ts>2026-05-17 07:29:41 -0700</creation_ts>
          <short_desc>[Navigation API] Private Browsing leaves navigation.currentEntry stale after intercepted same-origin cross-document navigation</short_desc>
          <delta_ts>2026-05-17 11:09:29 -0700</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>1</classification_id>
          <classification>Unclassified</classification>
          <product>WebKit</product>
          <component>DOM</component>
          <version>Safari 26</version>
          <rep_platform>Unspecified</rep_platform>
          <op_sys>Unspecified</op_sys>
          <bug_status>NEW</bug_status>
          <resolution></resolution>
          
          
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P2</priority>
          <bug_severity>Normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="k8o">kosakanoki</reporter>
          <assigned_to name="Nobody">webkit-unassigned</assigned_to>
          <cc>basuke</cc>
    
    <cc>cdumez</cc>
    
    <cc>rupin</cc>
          

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>2211521</commentid>
    <comment_count>0</comment_count>
    <who name="k8o">kosakanoki</who>
    <bug_when>2026-05-17 07:29:41 -0700</bug_when>
    <thetext>## Summary

In Private Browsing (Reproduced on 26.3.1 and 26.4), after `NavigateEvent.intercept({ handler })`
commits an intercepted same-origin cross-document navigation:

- `location.href` is updated to the new URL (correct)
- `navigation.currentEntry.url` and `.id` are NOT updated — they still
  reference the previous entry
- `currententrychange` event does NOT fire
- `navigatesuccess` event fires, but `navigation.currentEntry` still
  reports the previous entry at that point

The same code works correctly in non-private Safari 26.4 and in Chrome
(any mode), so this is specific to WebKit Private Browsing.

This affects routing code that follows the Navigation API contract by
reading `navigation.currentEntry` (and listening to `currententrychange`)
after an intercepted navigation commits.

## Steps to Reproduce

Save the HTML below as `index.html` and serve it from an HTTP origin,
for example:

```
python3 -m http.server 8000
```

Then open `http://localhost:8000/index.html` in a Safari **Private
Browsing** window. The `./next` resource does **not** need to exist; the
navigation is same-origin and intercepted before loading a new document.

```html
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
  &lt;a id=&quot;link&quot; href=&quot;./next&quot;&gt;click me&lt;/a&gt;
  &lt;pre id=&quot;log&quot;&gt;&lt;/pre&gt;
  &lt;script&gt;
    const $log = document.getElementById(&quot;log&quot;);
    const out = (label, data) =&gt; {
      const line = label + &quot; &quot; + JSON.stringify(data);
      $log.textContent += line + &quot;\n&quot;;
      console.log(line);
    };

    if (!(&quot;navigation&quot; in window)) {
      out(&quot;unsupported&quot;, { ua: navigator.userAgent });
    }

    navigation.addEventListener(&quot;navigate&quot;, (event) =&gt; {
      const beforeId = navigation.currentEntry?.id;
      out(&quot;navigate&quot;, {
        dest: event.destination.url,
        canIntercept: event.canIntercept,
        sameDocument: event.destination.sameDocument,
        navigationType: event.navigationType,
        beforeCurrentUrl: navigation.currentEntry?.url,
      });
      if (!event.canIntercept) return;
      event.intercept({
        handler: async () =&gt; {
          out(&quot;handler&quot;, {
            locationHref: location.href,
            currentEntryUrl: navigation.currentEntry?.url,
            currentEntryId: navigation.currentEntry?.id,
            currentEntryUnchanged: navigation.currentEntry?.id === beforeId,
          });
        },
      });
    });

    navigation.addEventListener(&quot;currententrychange&quot;, (e) =&gt; {
      out(&quot;currententrychange&quot;, {
        navigationType: e.navigationType,
        currentEntryUrl: navigation.currentEntry?.url,
      });
    });

    navigation.addEventListener(&quot;navigatesuccess&quot;, () =&gt; {
      out(&quot;navigatesuccess&quot;, {
        locationHref: location.href,
        currentEntryUrl: navigation.currentEntry?.url,
        currentEntryId: navigation.currentEntry?.id,
      });
    });
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
```

Click &quot;click me&quot;. The browser attempts a same-origin cross-document
navigation to `./next`; the script intercepts it via
`event.intercept({ handler })`.

## Expected (matches non-private Safari behavior and Chrome)

```
navigate            beforeCurrentUrl: &quot;.../index.html&quot;
currententrychange  navigationType:&quot;push&quot;, currentEntryUrl:&quot;.../next&quot;
handler             currentEntryUrl:&quot;.../next&quot;, currentEntryUnchanged:false
navigatesuccess     locationHref:&quot;.../next&quot;,  currentEntryUrl:&quot;.../next&quot;
```

## Actual (Safari 26.4 Private Browsing)

```
navigate            beforeCurrentUrl: &quot;.../index.html&quot;
handler             locationHref:&quot;.../next&quot;,
                    currentEntryUrl:&quot;.../index.html&quot;,
                    currentEntryUnchanged:true
navigatesuccess     locationHref:&quot;.../next&quot;,
                    currentEntryUrl:&quot;.../index.html&quot;   (STALE)
```

`currententrychange` never fires. `navigation.currentEntry` continues to
return the previous entry — both `.url` and `.id` are stale — for the
rest of the document&apos;s lifetime, until a reload occurs.

## Environment

- Safari 26.3.1 on macOS Tahoe 26.3.1
- Safari 26.4 on iOS 26.4.2
- Reproduces in macOS Safari Private Browsing windows
- Reproduces in iOS Safari Private tabs
- Does NOT reproduce in macOS / iOS Safari normal windows
- Does NOT reproduce in Chrome (any mode including Incognito)

## Related Bugs

- Bug 298466 — `[Navigation API] Push operation does not always create a
  new history item`. Appears related because it also concerns Navigation
  API push/entry creation for intercepted navigations. This report is
  narrower: it reproduces only in Private Browsing, uses a different
  destination URL, and additionally observes that `location.href` updates
  while `navigation.currentEntry` and `currententrychange` remain
  stale/missing.

## Impact

- The user-visible symptom is &quot;URL bar changes but page content stays the
  old one until reload&quot; in Private Browsing for applications that use the
  Navigation API for client-side routing.
- Any application following the documented Navigation API SPA pattern
  (read `navigation.currentEntry` on `currententrychange` to update the
  view) is affected.

## Workaround for Web Developers

Derive the current URL from `location.href` in Private Browsing; do not
rely on `navigation.currentEntry.url` or the `currententrychange` event
for this case. (Subscribing to `navigatesuccess` does not help on its
own because `navigation.currentEntry` is still stale at that point.)</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>