Skip to content

tab_clip right after tabs_load fails with "Missing host permission for the tab"; identical retry succeeds #20

Description

@mlsimon734

Observed live on Zen 153.0.1 (Firefox 153), signed install 0.2.0.2, driving the bridge from Gullet.

Sequence

>>> tabs_load {"tabIds":[1235]}
<<< {"tabs":[{"tabId":1235,"status":"ready","url":"https://transluce.org/"}],"ready":1,"pending":0,"failed":0}

>>> tab_clip {"tabId":1235,"vault":"test","close":true}
<<< ERROR {"error":"extract-failed","message":"Missing host permission for the tab"}

>>> tab_clip {"tabId":1235,"vault":"test","close":true}   # identical call, seconds later
<<< (succeeded — extraction, clip, verification all fine)

Same tab, same URL, same session. The tab had been clipped successfully by this same install ~20 minutes earlier, so the permission was genuinely held throughout; nothing about the grant changed between the two calls.

Where the message comes from

It is not ours. readTab surfaces result.error verbatim (src/bridge-methods.ts:586), so this is Gecko's own scripting.executeScript rejection. The hasOrigins(CLIP_ORIGINS) check just above it passed — the extension does hold *://*/* — which is why it fell through to extract-failed rather than the not-enabled branch with its remedy text.

Note the tab had also passed both guards immediately before: isHttpUrl(tab.url) was true (so the URL had committed — not the about:blank case documented in AGENTS.md) and tab.discarded was false.

Hypothesis (not verified)

A window after tabs_load where the tab reports status: "complete" and a committed URL, but its principal is not yet the page's, so Gecko evaluates the host-permission check against the wrong principal. ensureTabReady resolves on onUpdated "complete", which may precede scriptability. Alternative: an unrelated transient in executeScript after a discard/reload cycle. The observation does not separate these.

Why it matters

Wake-then-clip is the batch triage flow the bridge exists for — tabs_load a batch of survivors, then clip them. A transient failure there makes that flow flaky, and the error text sends the reader after a permissions problem that does not exist. An agent seeing it would plausibly tell the user to re-grant site access, or skip the tab as unreadable.

Possible directions

  • Retry extract once on this specific rejection before reporting failure.
  • Probe scriptability rather than trusting status: "complete" — a trivial executeScript after the reload, the way ensureTabReady already owns readiness for both callers.
  • At minimum, do not surface a raw engine string that names permissions when the permission check we can make has just passed; say the extraction failed transiently and suggest a retry.

Reproduction is intermittent — one failure in this session, on the first clip after a wake. Not seen without a preceding tabs_load.

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