fix(oc-docs): contextual error messages for failed try-it requests (BRU-3408)#40
Open
sundram-bruno wants to merge 2 commits into
Open
Conversation
…RU-3408)
A failed try-it request previously showed an opaque "Request Failed /
Failed to fetch" and hardcoded every network failure as a "CORS error" —
including connection-refused and timeouts. Timeouts were also missed
entirely (the catch checked for `AbortError`, but `AbortSignal.timeout()`
throws a `TimeoutError`), so they leaked the raw "signal timed out".
Browser fetch collapses CORS, DNS, connection-refused, offline, and TLS
into one opaque `TypeError: Failed to fetch`, so only two states are
actually distinguishable in code: timeout and opaque. Anything else is
reported as uncategorized rather than guessed at.
Changes:
- Add `classifyRequestError` — a pure classifier returning a structured
{ type, title, message, hint } for the three states (timeout / opaque /
uncategorized). The opaque message is CORS-first but hedged, and names
the file-origin `null` case, without asserting CORS as certain.
- RequestExecutor delegates its catch to the classifier; remove the
hardcoded CORS string and the dead network/ssl branches that fetch can
never produce.
- Add a reusable `ErrorBanner` UI (bold title, monospace message, optional
next-step hint) mirroring Bruno desktop's response error banner.
- Render the banner inside the Response tab (keeping the tab shell) and
hide the status bar on failure, since no HTTP status exists.
- 4xx/5xx remain normal responses (not failures).
Tests:
- Unit: classifyRequestError — all three states plus edge cases.
- E2E: opaque banner renders in the Response tab, never mislabels as a
definite CORS error, and a 4xx renders normally.
Out of scope (separate follow-ups): script/assertion error display, and
response-body view modes (rendered HTML / preview).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Refine the failure classification per the updated ticket: instead of one opaque "almost always CORS" bucket, classify from the request context the browser does expose — whether it timed out, the page vs target scheme, and same-origin vs cross-origin / file. Five cases: - timeout -> "Request timed out. The server didn't respond in time." - mixed-content -> secure page (https) calling an insecure (http) URL - browser-blocked -> cross-origin, or docs opened from a file (CORS) - unreachable -> same-origin failure (server down / wrong URL) - unknown -> the underlying error message Same-vs-different is compared by ORIGIN (scheme+host+port), not site, since CORS is enforced per-origin. CORS is now suggested only for cross-origin or opened-from-file failures, never same-origin (AC opencollection-dev#2). An unparseable request URL (e.g. an unresolved {{var}}) falls through to the underlying message. classifyRequestError now takes the resolved request URL and the page URL (window.location.href, passed in to keep it pure). The errorHint field is dropped — the new copy embeds the next step in the message. Response display, default timeout, and OAuth2 handling are unchanged. Tests reworked to cover all five cases (unit) and browser-blocked, same-origin-unreachable, and 4xx-not-a-failure (e2e). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sachin-bruno
approved these changes
Jun 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A failed try-it request in the collection docs showed only an opaque "Request Failed / Failed to fetch", and the runner hardcoded every network failure as a
"CORS error"— including connection-refused, same-origin, and timeouts (see opencollection #24). Timeouts were also missed: the catch checked forAbortError, butAbortSignal.timeout()throws aTimeoutError, so real timeouts leaked the raw"signal timed out".Approach
Browser
fetchcollapses CORS, DNS, connection-refused, offline, and TLS into one opaque failure with no detail — the real cause lives only in devtools. So we classify from the request context the browser does expose (timeout, page vs target scheme, same-origin vs cross-origin / file), not the error text.Five cases
https, targethttpSame-vs-different is compared by origin (scheme+host+port), not site, because CORS is enforced per-origin (
https://docs.example.com→https://api.example.comis cross-origin even though both areexample.com). CORS is suggested only for cross-origin or opened-from-file failures, never same-origin (AC #2).Changes
classifyRequestError— pure classifier returning{ type, title, message }; takes the resolved request URL + the page URL (window.location.href, passed in to stay pure). Unparseable URL → underlying message.RequestExecutor— catch delegates to the classifier; removed the hardcoded CORS string and the deadnetwork/sslbranchesfetchcan never produce.ErrorBanner— small reusable UI (bold title + monospace message) mirroring Bruno desktop's response error banner.ResponsePane— banner renders inside the Response tab (consistent with a success response); status bar hidden on failure (no HTTP status exists).4xx/5xxremain normal responses. Response display, default timeout, and OAuth2 handling are unchanged.Tests
classifyRequestError.spec.ts): all five cases + edges (cross-origin, file origin, same-origin never-CORS, unparseable URL, non-Error throw).request-errors.spec.ts): cross-origin → browser-blocked (inside Response tab), same-origin → unreachable (never mentions CORS), 4xx → renders normally. First e2e to actually drive Try → Send; usespage.routefor deterministic failures.All existing e2e (63) and unit tests pass; new code is lint-clean.
Acceptance criteria
Out of scope (follow-ups)
🤖 Generated with Claude Code