Skip to content

fix: window ID becomes stale after full-page navigation — this._page not updated on CDP target recreate #960

@elias-didoo

Description

@elias-didoo

Problem

After opencli browser open followed by a full-page navigation (not a modal overlay), all subsequent CDP commands fail with No window with id.

Working cases (modal overlay URLs — no CDP target reset):

  • postx.com/compose/tweet
  • replyx.com/compose/post?in_reply_to=...

Broken cases (full-page navigation — triggers CDP target recreate):

  • followx.com/{username}
  • likex.com/status/...
  • searchx.com/explore → SPA navigation ❌
  • timeline → page.evaluate on current page ❌

Root Cause

In src/browser/page.js, the goto() method:

  1. Calls sendCommandFull('navigate', { url, ...this._cmdOpts() }) where this._cmdOpts() includes the stale this._page (the old/失效的 target ID)
  2. The navigate action destroys the old CDP target and creates a new one
  3. The new target's ID is returned in result.page, and goto() correctly saves it: this._page = result.page
  4. BUT the subsequent sendCommand('exec', ...) call at line ~45 uses the same this._cmdOpts() — which still contains the old page field from before the assignment

The sendCommand('exec', ...) is made inside the if (options?.waitUntil !== 'none') block before this._page = result.page takes effect for that call, because this._cmdOpts() is evaluated before the assignment.

Even when the exec call is retried after a settle error, it still uses the old this._page.

Impact

PR #892 (retry on No window with id CDP error) was merged but did not fully fix this — it addressed the retry classification layer but not the root cause: this._page becoming stale after a full-page navigation that triggers a CDP target recreate.

Suggested Fix

The sendCommand('exec', ...) call after navigate should use the new page identity, not the old one. Options:

  1. Inline the new page ID into the exec call — pass page: result.page directly instead of relying on this._cmdOpts()
  2. Re-bind after navigate — call selectTab(0) or bindCurrentTab after navigate to ensure this._page is fresh
  3. Don't cache page identity in goto() at all — always fetch the current active page fresh for each command (simplest, but may have performance implications)

Test Script

opencli browser open https://x.com
opencli twitter follow elonmusk  # fails: No window with id
# vs
opencli browser open https://x.com/compose/tweet
opencli twitter post "test"  # works: modal overlay, no target reset

Environment

  • OpenCLI v1.7.0
  • macOS
  • Chrome Extension automation

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions