fix(server): type no-tab rejections so they stop reading as version mismatches - #205
Conversation
…ismatches `classifyBridgeError` dispatches on error type, not message, so "no tab matching <url>" arrived as a plain FetchproxyProtocolError and inherited whatever blanket advice a consumer gives `protocol` errors. In the CLI that advice is "extension/server version mismatch — update both", so a user on a current CLI and a current extension was sent to update both: bridge error (protocol): no tab matching https://api.creditkarma.com/ — extension/server version mismatch — update both. Nothing was mismatched. Nothing was open on that host. This is the same misdirection FetchproxyScopeError was introduced to stop, so it gets the same treatment: a FetchproxyNoTabError carrying the remedy on `.hint`, built by `protocolErrorFrom` like every other typed rejection. Two things beyond the obvious fix: `FetchproxyHintedError` now holds the shared originalError/hint shape, and the CLI branches on that base rather than on FetchproxyScopeError. Keying on the concrete subclass is precisely how this bug happened — the next hinted error would have inherited the wrong blanket advice too. Existing `instanceof FetchproxyScopeError` and `instanceof FetchproxyProtocolError` catches are unaffected. The "matched a tab but its content script never answered" wording is deliberately excluded. Its remedy is to refresh the page, not to open one, and the extension's message already says so — retyping it would staple contradictory advice onto it. Verified live against the original reproduction: no tab matching https://api.creditkarma.com/ — open a tab on that host and sign in, then re-run. This is not a version problem… Closes #204 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012o2nXwu7tov6j7ciBEpigo
|
Claude finished @chrischall's task in 2m 8s —— View job Reviewing PR #205
ReviewThe fix introduces Verified in detail:
No correctness, convention, or test-coverage issues found. No issues found. Verdict: pass Branch: |
|
✅ Auto-review verdict: pass — The fix correctly types no-tab rejections via a new FetchproxyNoTabError sharing a FetchproxyHintedError base with FetchproxyScopeError; regex, class hierarchy, and CLI branch were all verified against source and no regressions or convention violations were found. |
🤖 I have created a release *beep* *boop* --- ## [2.0.0](v1.11.0...v2.0.0) (2026-08-06) ### ⚠ BREAKING CHANGES * **protocol:** bind the ephemeral key into the ready signature ([#222](#222)) ### Features * **protocol:** add write_cookies, the one verb that can repair a rotated session ([#211](#211)) ([b2557c2](b2557c2)) * **protocol:** bind the ephemeral key into the ready signature ([#222](#222)) ([c13aeed](c13aeed)) * **server:** let a request name the tab that relays it ([#207](#207)) ([c5d3f4d](c5d3f4d)) * **server:** pin the extension's identity, and verify it on the peer path ([#213](#213)) ([0eeced7](0eeced7)) ### Bug Fixes * **cli:** let a real filesystem error be itself, not "no extension pin" ([#221](#221)) ([c87a864](c87a864)), closes [#220](#220) * **cli:** validate --via-tab before connecting, like the request URL ([#210](#210)) ([959fcc5](959fcc5)) * **extension:** reattach the write_cookies doc block, and name the writable cookies as writable ([#215](#215)) ([2730c4a](2730c4a)) * **extension:** use the guarded caps local for the cookie heading ([#217](#217)) ([f95c832](f95c832)) * **server:** release only our own extension claim, and stop guessing scoped names ([#219](#219)) ([3d90a64](3d90a64)), closes [#218](#218) * **server:** type no-tab rejections so they stop reading as version mismatches ([#205](#205)) ([dc30bd9](dc30bd9)) ### Refactor * **server:** drop the concatBytes imports the signature change orphaned ([#224](#224)) ([4985ba7](4985ba7)), closes [#223](#223) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Closes #204.
Correction to the issue
The issue blamed
error-kind.ts:88and a missing key in the CLI's hint table. That was the wrong classifier.classifyFetchError(error-kind.ts) is what MCP consumers use on fetch results; the CLI usesclassifyBridgeError, which dispatches on error type:So a no-tab rejection was never going to be anything but
protocol, and adding ano_tabkey to the hint table would have done nothing. The symptom and the remedy were right; the mechanism was not.The fix
FetchproxyNoTabError, built byprotocolErrorFromlike every other typed rejection, carrying the remedy on.hint. Same shape asFetchproxyScopeError, which exists for exactly this reason.Before
After (verified live against the original reproduction)
Two decisions worth reviewing
FetchproxyHintedErroras a shared base. The CLI now branches on that rather thanFetchproxyScopeError. Keying on the concrete subclass is how this bug happened — a hinted error that wasn't a scope error fell through to the blanket advice. With the base, the next hinted error renders correctly with no new branch.FetchproxyScopeErrorkeeps its own identity and ancestry, so existinginstanceofcatches are unaffected either way.The content-script variant is deliberately excluded.
no tab matching <url> has the fetchproxy content script loaded (N URL matches, none responded)means a tab did match — the remedy is to refresh the page, not open one, and the extension's own message already says so. The regex uses a negative lookahead rather than a bare prefix match, and there's a test pinning that.Tests
1142 pass across the monorepo (up from 1140). New
packages/server/tests/no-tab-error.test.tscovers the typing, the hint content, the raw-error preservation, back-compat withFetchproxyProtocolError/classifyBridgeError, the excluded content-script wording, and non-collision with scope errors — plus a shared-contract block asserting both hinted subclasses render identically. Two CLI tests cover the rendered output.Note
Anyone on the published CLI (1.4.0) still sees the old hint until the CLI ships too — the branch on
FetchproxyHintedErrorlives inpackages/cli. That's how I first "verified" this and got the old string back: the linked local server was producing the new error, but the npm CLI didn't recognise it.🤖 Generated with Claude Code
https://claude.ai/code/session_012o2nXwu7tov6j7ciBEpigo