Skip to content

A /about redirect on flow.google.com is reported as UiSelectorDriftError (exit 23) #756

Closed

Description

@ffroliva

Measured 2026-09-08 on ci-probe while instrumenting #719. $0.

What happens

MigratedComposer.ensure_editor navigates to flow.google.com/project/<id>, the app redirects to flow.google.com/about, the settings trigger is of course never there, and 30 s later:

UiSelectorDriftError (exit 23): migrated host: the settings trigger (.settings-trigger-button)
did not become visible within 30s on https://flow.google.com/about (host=migrated)

The URL is in the message, and that is the only reason this was diagnosable at all — credit where due to whoever put it there.

Why it is wrong

/about is Flow's public landing page. Ending up there is not selector drift; it is the app telling us this session cannot open that project on this host. Reporting it as drift sends the user to "check for a newer gflow-cli release, then file a bug" over an account/session state no release will change — the same manufactured-drift-report problem #721 fixed for credit shortfalls, and #749 for agent mode. That is now three instances of one pattern, which is what makes it worth a general guard rather than a third special case.

What makes this confusing

gflow auth status --profile ci-probe reports the Flow session verified (compiledgrownth.official@gmail.com), and gflow project list --profile ci-probe works and lists the project. So every check a user would run says "you are signed in", and only the migrated editor disagrees.

Suggested shape

The check is cheap and needs no new anchor — after page.goto, the URL either is the project or it is not:

if not page.url.startswith(MIGRATED_PROJECT_URL.format(project_id=project_id)):
    # landed somewhere else entirely (/about, a sign-in page, a different project)

The existing flow_host_kind / goto-redirect plumbing from #639/#644 is next door, and goto returning before the client-side redirect is a trap already recorded on this path — so the check belongs where the run already blocks (the readiness wait), not in a new bounded wait after goto.

Not measured

  • Why ci-probe is redirected. Signed out on flow.google.com specifically, a cohort gate, or a project-access problem are all consistent with one observation. This issue is only about the reporting, not the cause — do not let a fix assert a cause it has not measured.
  • Whether the same redirect can happen mid-session on an account that worked a minute earlier.

Refs #719, #721, #749, #639

Activity

  1. ffroliva commented on Sep 8, 2026

    @ffroliva
    OwnerAuthor

    Follow-up measurement — the landings are distinguishable, which makes the fix sharper than what I filed above. Four navigations, two profiles, $0:

    Navigation Lands on
    ci-probe → labs.google/fx/tools/flow accounts.google.com/…/signin/accountchooser
    ci-probe → its own project flow.google.com/about
    ffroliva → its own project flow.google.com/project/<id>
    ffroliva → ci-probe's project flow.google.com/404?reason=project

    So my "Not measured" note above is now partly answered, and one guess in it was wrong:

    • /about = signed out. Confirmed independently by the labs root redirecting to the OAuth account chooser on the same profile.
    • 404?reason=project = signed in, no access to that project. A different URL, so the two states this issue lumped together are separable at zero cost.

    That means the fix should name three outcomes, not two:

    /project/<id>       -> good
    /about              -> this profile is signed out on flow.google.com; run `gflow auth login`
    /404?reason=project -> signed in, but this account cannot open that project
    anything else       -> genuinely unexpected; keep the current drift message
    

    The last row matters — this should not become a guard that swallows real drift. Anything not on the known list stays exit 23 with the URL, which is what made this diagnosable in the first place.

    The confusing part now has a mechanism

    gflow auth status --profile ci-probe reports the session verified, and gflow project list returns three projects, while the browser is signed out. Those are two different lanes: the REST lane rides the NextAuth token (__Secure-next-auth.session-token) and still works; the browser lane needs the Google SSO session, which is gone. Only generation uses the broken one.

    So auth status is not merely unhelpful here, it is actively misleading — it checks the lane that still works. Worth deciding whether that is part of this issue or its own; I have not filed it separately.

    Not measured: why the browser session died, or when.

  2. added 2 commits that reference this issue on Sep 8, 2026
  3. Mauryanx commented on Sep 9, 2026

    @Mauryanx
    Contributor

    Adding evidence from my macOS v0.71.1 failure to this issue, following the existing follow-up measurement rather than opening another landing-classification issue.

    The same contradiction appears in my run:

    • Fresh login reported success, and the REST credits request succeeded with HTTP 200.
    • The Python reader logged cookie_decryption_failed_falling_back_to_playwright. The fallback browser saw the labs-scoped __Secure-next-auth.session-token, but no exact-name SAPISID in its full jar.
    • Generation found the existing labs session cookie, so its session-cookie seeding branch did not run.
    • migrated.dispatch mode=t2v selected the migrated composer, navigation reached /about, and the missing settings trigger was reported as UiSelectorDriftError (exit 23).

    This adds a Mac incident to the healthy-REST/signed-out-browser pattern already measured here. Missing or invalid Google SSO in the migrated browser lane is the strongest supported explanation, but my evidence does not identify when SSO was lost. Missing SAPISID means exactly that cookie was not visible to the reader, not that every possible Google credential was absent. /about alone does not exclude every Google-side gate without the rendered state and redirect evidence.

    The distinction worth preserving in diagnostics is REST session validity versus migrated browser readiness. At the analyzed source revision, credits obtains a labs-derived bearer credential and does not require the snapshot's Google-session boolean. Auth verification also validates the labs session. These are valid checks of that lane; their success is not proof that the migrated editor is ready.

    This is the reverse of #644's original latent scenario: labs remains valid while browser SSO fails. It does not establish that the original labs-dead/SSO-alive scenario occurred, or justify forwarding Google cookies through the labs-only HTTP dictionary. Likewise, replacing a live readiness check with a cookie-presence assertion would not establish readiness.

    The existing proposal to classify landings at the readiness/redirect-settle boundary fits this evidence. Preserve the distinction between measured sign-in/chooser and project-access failures, keep unexpected-route evidence and real editor selector failures visible, and capture the incident before parking the page. An extra arbitrary wait immediately after goto would miss the point about late client-side redirects already recorded here. Diagnostic wording alone will not repair SSO.

    Mac verification still needs the same-profile comparison: healthy labs session with signed-out browser SSO should produce an actionable session diagnosis; an inaccessible project should remain distinguishable; after SSO repair, observe actual editor readiness. The cause of the Mac cookie-reader failure is a separate investigation, not proven by this landing.

    I have omitted cookie values, account identifiers, profile paths, authentication URLs and the raw incident bundle. No new live run is claimed in this comment.

  4. added 2 commits that reference this issue on Sep 10, 2026
    126a6b8
    3cc8271
  5. ffroliva commented on Sep 11, 2026

    @ffroliva
    OwnerAuthor

    Reopening context rather than the issue — two measurements landed today that narrow this, both from catching a live occurrence on denon82 while working on #780.

    A retry is doomed (PR #785). The stability probe this issue produced was re-run unmodified during a live occurrence, so its pre-registered reading governs: 5/5 attempts landed on /about over ~3 minutes, 31–35 s each, on the account's own project with a healthy session. retryable=False was a preserved default and both the code comment and FlowAppError's docstring said so; it is now the measured answer. Behaviour unchanged.

    The cause is narrowed, not named (PR #786). An A/B against a working account on the wire:

    denon82 (fails) ci-probe (control)
    document 200, no Location 200, no Location
    hop to /about 338 ms —
    batchexecute calls 0 20, first at 275 ms
    non-2xx from Flow none none

    So it is not a server-side redirect, and the app decides without asking Flow anything — not called and refused, never called. There is no permissions call to point at. Account-wide rather than project-specific (a second project, 2/2). And gflow project list returns the redirecting project, so the backend grants access while the frontend declines to open it.

    The signal is therefore present at page load rather than fetched. Which signal is not named: that means reading the document's embedded bootstrap payload, which is where bearer tokens and account data live on this origin, and it was not read. Your warning here stands — a lead is not a cause.

    What would settle it: a HAR capture of the failing document through scripts/dev/har-spike/, diffed against a working one, with extract_har_summary.py producing the shareable summary.

    Practical takeaway for whoever picks this up: looking for a refused permissions call is a dead end.

    https://claude.ai/code/session_01Nr4XuvvZv3PrL3pKEzkrLc

  6. added a commit that references this issue on Sep 12, 2026
    bbc7f00
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions