Skip to content

Keep the expected managed settings 404 out of the DevTools console - #331024

Draft
joshspicer wants to merge 1 commit into
mainfrom
agents/suppress-404-logs-in-dev-tools
Draft

Keep the expected managed settings 404 out of the DevTools console#331024
joshspicer wants to merge 1 commit into
mainfrom
agents/suppress-404-logs-in-dev-tools

Conversation

@joshspicer

@joshspicer joshspicer commented Aug 15, 2026

Copy link
Copy Markdown
Member

Problem

Developer Tools logs this repeatedly, and it looks like a failure:

api.github.com/copilot_internal/managed_settings:1  Failed to load resource: the server responded with a status of 404 ()

The 404 is not a problem — it is how the endpoint says "this account has no managed settings", and DefaultAccountProvider already handles it as a normal outcome. The problem is purely that it gets printed.

Why it can't be fixed in the renderer

Chromium emits that line from the document's network stack for any response with an error status. Measured via the DevTools Log domain (Log.entryAdded, which is exactly what the console renders):

request from the renderer printed?
fetch yes
XMLHttpRequest yes
fetch + keepalive / cache: 'no-store' yes
same, inside an iframe yes

There is no request option that suppresses it, and it is not a console.* call that could be filtered.

Fix

Rewrite the status in the main process before the response reaches the window, using the same session.defaultSession.webRequest.onHeadersReceived mechanism that already sits a few lines above in app.ts (used to add Access-Control-Allow-Origin for the PRSS CDN). The real status travels in a response header that the workbench restores immediately, so every downstream code path still sees the 404 it sees today — including the retry-next-session logic and the noSettings handling.

Scope is deliberately tight: only a 404, only from https://api.*/copilot_internal/managed_settings (covering GHES, whose host is also api.-prefixed). Any other status, endpoint or genuine failure is reported exactly as before.

One subtlety worth flagging for review: the request is cross-origin, so the marker header is invisible to the window unless it is added to Access-Control-Expose-Headers. That list is extended, not replaced — replacing it would hide the x-ratelimit-remaining / retry-after headers that the rate-limit logic reads off this same response.

Verification

Ran the shipped predicate and handler verbatim in Electron (the .build/electron binary this repo uses), against a real https://api.github.com/copilot_internal/managed_settings?client_id=… URL served by a local HTTPS endpoint that mimics GitHub's response (CORS, its own access-control-expose-headers, x-ratelimit-remaining), with the DevTools Log domain attached:

managed_settings (real URL + query)
   renderer: {"status":200,"original":"404","rateLimit":"4999","body":"{\"message\":\"Not Found\"}"}
   console : silent
other copilot endpoint (untouched)
   renderer: {"status":404,"original":null,"rateLimit":"4999","body":"{\"message\":\"Not Found\"}"}
   console : PRINTS -> Failed to load resource: the server responded with a status of 404 (Not Found)

So: the noise is gone, the true status is recovered, the rate-limit headers survive, and neighbouring endpoints are unaffected.

Also: scripts/test.sh on the three related suites (53 passing, including new unit tests for the URL predicate and the status restore), plus tsc -p src/tsconfig.json, eslint, and valid-layers-check.

Notes

  • Desktop only. The web workbench still prints it; that would need the service to stop answering 404.
  • While investigating I found a separate, unrelated inefficiency: findMatchingProviderSession lists one session once per scope set it matches, so a full-scope GitHub session is listed 3× and the identical request is sent 3× with the same token. That is a real bug but it is not the cause of the printing, so I have left it out of this PR — happy to send it separately.

Copilot AI balanced review requested due to automatic review settings August 15, 2026 15:45
@vs-code-engineering

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

Robo (@deepak1556)

Matched files:

  • src/vs/code/electron-main/app.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds desktop request routing to prevent expected Copilot API failures from cluttering renderer DevTools.

Changes:

  • Adds an expected non-success request hint.
  • Routes flagged desktop requests through the main process.
  • Applies the hint to Copilot account requests.
Show a summary per file
File Description
src/vs/base/parts/request/common/request.ts Adds the request hint.
src/vs/code/electron-main/app.ts Registers the main-process request channel.
src/vs/workbench/services/request/electron-browser/requestService.ts Routes flagged requests through IPC.
src/vs/workbench/services/accounts/browser/defaultAccount.ts Flags Copilot account requests.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Suppressed comments (1)

src/vs/workbench/services/request/electron-browser/requestService.ts:51

  • This main-process path no longer honors cancellation or timeout while the response body is being read. RequestChannel buffers the body only after the main IRequestService.request resolves, but the Node request implementation clears its timeout and cancellation listener as soon as response headers arrive; unlike the renderer fetch(...).arrayBuffer() path, a stalled body can therefore hang startup/account resolution indefinitely. Keep the token and timeout active through IPC body buffering before routing these requests here.
		if (options.expectNonSuccessStatus) {
			return this.logAndRequest(options, () => this.mainProcessRequestClient.request(options, token));
  • Files reviewed: 4/4 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment on lines +58 to +70
/**
* A signal that a non-2xx response is an expected outcome of this request
* (e.g. `404` meaning "nothing is configured") and therefore must not be
* reported as a failure to the user.
*
* Implementations that issue requests from a browser window can use this to
* run the request outside of the renderer: Chromium unconditionally logs
* `Failed to load resource: the server responded with a status of 404` into
* the Developer Tools console for every `fetch` that resolves with an error
* status, which is confusing noise for an expected outcome. This may not be
* supported in all implementations.
*/
expectNonSuccessStatus?: boolean;
Comment on lines +24 to +30
/**
* Requests that expect a non-2xx response are made from the main process:
* Chromium logs every `fetch` that resolves with an error status into the
* Developer Tools console of the window that issued it, which is confusing
* noise when that status is an expected outcome.
*/
private readonly mainProcessRequestClient: RequestChannelClient;
Comment thread src/vs/code/electron-main/app.ts Outdated
Comment on lines +1405 to +1409
// Request (for requests that must not run in a window, e.g. because a
// non-2xx response is expected and Chromium would log it to the
// Developer Tools console of that window)
const requestChannel = new RequestChannel(accessor.get(IRequestService));
mainProcessElectronServer.registerChannel('request', requestChannel);
Comment on lines +1091 to +1093
// Non-2xx responses are routine here (e.g. `404` when the account has no
// managed settings). Keep them out of the window's Developer Tools console
// by having the request run outside of the renderer.
roblourens
roblourens previously approved these changes Aug 15, 2026
@joshspicer
joshspicer force-pushed the agents/suppress-404-logs-in-dev-tools branch from 494a59d to 3d5922e Compare August 15, 2026 18:52
@joshspicer joshspicer changed the title Keep expected 404s from the Copilot account endpoints out of the DevTools console Stop retrying the same auth session for every matching scope set Aug 15, 2026
roblourens
roblourens previously approved these changes Aug 15, 2026
@joshspicer
joshspicer marked this pull request as draft August 16, 2026 00:33
The Copilot managed settings endpoint answers `404` when an account simply
has no managed settings. The workbench already treats that as the normal
"no settings" outcome, but Chromium unconditionally logs

    Failed to load resource: the server responded with a status of 404

into the Developer Tools console of the window that issued the request.
Nothing on the renderer side suppresses it: `fetch` and `XMLHttpRequest`
both emit it, in the top frame and in iframes, regardless of request
options.

Rewrite the status in the main process before the response reaches the
window — the same `onHeadersReceived` mechanism already used a few lines
above to add CORS headers for the PRSS CDN — and carry the real status in
a response header that the workbench restores before acting on the
response. Only a `404` from that one endpoint is rewritten, so every other
request, and every genuine failure, is reported exactly as before.

The header has to be added to `Access-Control-Expose-Headers` for the
window to read it back, because the request is cross-origin. That list is
extended rather than replaced so the rate-limit headers the workbench
reads off the same response stay visible.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@joshspicer
joshspicer force-pushed the agents/suppress-404-logs-in-dev-tools branch from 3d5922e to 82ffe51 Compare August 16, 2026 00:49
@joshspicer joshspicer changed the title Stop retrying the same auth session for every matching scope set Keep the expected managed settings 404 out of the DevTools console Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants