You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Workspace chunk search's external ingest index throws an unhandled ExternalIngestRequestError: POST external-embeddings-code-search failed with status 404 when the remote embeddings index is not yet ready. The code already recognizes a 404 as the benign "index not ready yet" state and retries once after a 2s delay, but if the second attempt also returns 404 the error is re-thrown and surfaces as unhandled-error telemetry. Impact: noisy error telemetry (and a failed local-diff search leg) for a normal, transient service state during first index / large workspace.
Add slight retry on first external ingest search failure
Why
This commit introduced the single-retry workaround at externalIngestIndex.ts:485-489. It classifies a 404 as the expected "index not ready" state and retries once, but the retried call's own 404 is not caught, so a persistent not-ready state re-throws instead of degrading to an empty result.
Code Flow
sequenceDiagram
participant Search as CodeSearchChunkSearch.searchLocalDiff
participant Index as ExternalIngestIndex.search
participant Client as ExternalIngestClient.searchFilesets
participant API as githubApiFetcher
Search->>Index: search(sizing, query)
Index->>Client: searchFilesets() [attempt 1]
Client->>API: POST /external/embeddings/code/search
API-->>Client: 404 (index not ready)
Note over Index: catch 404 -> wait 2s, retry once
Index->>Client: searchFilesets() [attempt 2]
Client->>API: POST /external/embeddings/code/search
API-->>Client: 404 (still not ready)
Note over Client: 💥 throw ExternalIngestRequestError:<br/>"POST external-embeddings-code-search failed with status 404"
Client-->>Index: rethrow (not caught on retry)
Note over Index: reported via externalIngestIndex.search.error -> unhandled telemetry
L485-L490: if (err instanceof ExternalIngestRequestError && err.response.status === 404) { ... return await this._client.searchFilesets(...) } — retry re-throws on a persistent 404
Repro Steps
Open a large workspace (or one being indexed for the first time) with Copilot workspace chunk search / external ingest enabled.
Trigger a semantic workspace search (e.g. #codebase) while the remote embeddings index is still being built server-side.
The first searchFilesets call returns 404 (index not ready); after a 2s delay a second call also returns 404 because indexing hasn't finished.
The retried 404 re-throws and is recorded as an unhandled error (externalIngestIndex.search.error).
How the Fix Works
Chosen approach — externalIngestIndex.ts → ExternalIngestIndex.search(): wrap the single retry searchFilesets call in its own try/catch. When the retried call also fails with a 404, return undefined — the same value the method already produces for an empty/not-ready result, which the existing if (!searchResult || !searchResult.results) { return []; } guard at L505 turns into an empty result. Any non-404 error on the retry is still re-thrown unchanged, so genuine failures continue to surface via externalIngestIndex.search.error / the telemetry pipeline. This fixes the condition at its source: the code that already knows a 404 means "index not ready" now treats a persistent not-ready state as the benign empty result it is, rather than an error. No logService.error call is removed and no genuine error is swallowed — only the already-classified benign 404 is degraded to an empty result.
Alternatives considered: adding a broad try/catch at the outer searchLocalDiff/searchWorkspace call site — rejected because it would swallow unrelated errors and sits far from where 404 is already understood as benign, hiding real failures instead of handling the specific known-benign state at its origin.
Recommended Owner
@mjbvz — authored the culprit commit (5e1ee93d) and is the telemetry owner for externalIngestIndex.* events. Active in microsoft/vscode within the last 90 days.
Original error: ERR_API: [2026-08-11T15:17:11.446Z] create pull request in microsoft/vscode failed (attempt 1)
Original error: Validation Failed: {"resource":"PullRequest","code":"custom","field":"fork_collab","message":"fork_collab Fork collab can't be granted by someone without permission"} - https://docs.github.com/rest/pulls/pulls#create-a-pull-request
Retryable: false
Suggestion: This error cannot be resolved by retrying. Please check the error details and fix the underlying issue.
To create the pull request manually:
gh pr create --title "fix: treat persistent 404 from external ingest search as empty result (fixes #330268)" --base main --head vscodebot-pr:fix/external-ingest-persistent-404-8ef906b52b29e16a --repo microsoft/vscode
Show patch (37 lines)
From b4b2f1c017bd0b836c8232c512f7d7e6f83ac69c Mon Sep 17 00:00:00 2001
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Tue, 11 Aug 2026 15:10:20 +0000
Subject: [PATCH] fix: treat persistent 404 from external ingest search as
empty result (fixes #330268)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../node/codeSearch/externalIngestIndex.ts | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/externalIngestIndex.ts b/extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/externalIngestIndex.ts
index acc320a46f4..f74f8599eeb 100644
--- a/extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/externalIngestIndex.ts+++ b/extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/externalIngestIndex.ts@@ -486,7 +486,16 @@ export class ExternalIngestIndex extends Disposable {
// On the first index or a large workspace, there might be a slight delay on the service
// before the index is actually ready. Workaround by retrying just once after a short delay.
await raceCancellationError(timeout(2000), token);
- return await this._client.searchFilesets(filesetName, resolvedQuery, sizing.maxResultCountHint, callTracker, token);+ try {+ return await this._client.searchFilesets(filesetName, resolvedQuery, sizing.maxResultCountHint, callTracker, token);+ } catch (retryErr) {+ if (retryErr instanceof ExternalIngestRequestError && retryErr.response.status === 404) {+ // The index is still not ready. This is an expected, benign state (not an+ // error condition), so treat it as an empty result rather than throwing.+ return undefined;+ }+ throw retryErr;+ }
}
throw err;
}
--
2.54.0
Summary
Workspace chunk search's external ingest index throws an unhandled
ExternalIngestRequestError: POST external-embeddings-code-search failed with status 404when the remote embeddings index is not yet ready. The code already recognizes a 404 as the benign "index not ready yet" state and retries once after a 2s delay, but if the second attempt also returns 404 the error is re-thrown and surfaces as unhandled-error telemetry. Impact: noisy error telemetry (and a failed local-diff search leg) for a normal, transient service state during first index / large workspace.Fixes #330268
Recommended reviewer:
@mjbvzCulprit Commit
5e1ee93d@mjbvzexternalIngestIndex.ts:485-489. It classifies a 404 as the expected "index not ready" state and retries once, but the retried call's own 404 is not caught, so a persistent not-ready state re-throws instead of degrading to an empty result.Code Flow
sequenceDiagram participant Search as CodeSearchChunkSearch.searchLocalDiff participant Index as ExternalIngestIndex.search participant Client as ExternalIngestClient.searchFilesets participant API as githubApiFetcher Search->>Index: search(sizing, query) Index->>Client: searchFilesets() [attempt 1] Client->>API: POST /external/embeddings/code/search API-->>Client: 404 (index not ready) Note over Index: catch 404 -> wait 2s, retry once Index->>Client: searchFilesets() [attempt 2] Client->>API: POST /external/embeddings/code/search API-->>Client: 404 (still not ready) Note over Client: 💥 throw ExternalIngestRequestError:<br/>"POST external-embeddings-code-search failed with status 404" Client-->>Index: rethrow (not caught on retry) Note over Index: reported via externalIngestIndex.search.error -> unhandled telemetryAffected Files
extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/externalIngestClient.tsthrow new ExternalIngestRequestError(...failed with status ${response.status})extensions/copilot/src/platform/workspaceChunkSearch/node/codeSearch/externalIngestIndex.tsif (err instanceof ExternalIngestRequestError && err.response.status === 404) { ... return await this._client.searchFilesets(...) }— retry re-throws on a persistent 404Repro Steps
#codebase) while the remote embeddings index is still being built server-side.searchFilesetscall returns 404 (index not ready); after a 2s delay a second call also returns 404 because indexing hasn't finished.externalIngestIndex.search.error).How the Fix Works
Chosen approach —
externalIngestIndex.ts→ExternalIngestIndex.search(): wrap the single retrysearchFilesetscall in its owntry/catch. When the retried call also fails with a 404, returnundefined— the same value the method already produces for an empty/not-ready result, which the existingif (!searchResult || !searchResult.results) { return []; }guard at L505 turns into an empty result. Any non-404 error on the retry is still re-thrown unchanged, so genuine failures continue to surface viaexternalIngestIndex.search.error/ the telemetry pipeline. This fixes the condition at its source: the code that already knows a 404 means "index not ready" now treats a persistent not-ready state as the benign empty result it is, rather than an error. NologService.errorcall is removed and no genuine error is swallowed — only the already-classified benign 404 is degraded to an empty result.Alternatives considered: adding a broad
try/catchat the outersearchLocalDiff/searchWorkspacecall site — rejected because it would swallow unrelated errors and sits far from where 404 is already understood as benign, hiding real failures instead of handling the specific known-benign state at its origin.Recommended Owner
@mjbvz— authored the culprit commit (5e1ee93d) and is the telemetry owner forexternalIngestIndex.*events. Active inmicrosoft/vscodewithin the last 90 days.Note
This was originally intended as a pull request, but PR creation failed. The changes have been pushed to the branch
fix/external-ingest-persistent-404-8ef906b52b29e16a.Original error: ERR_API: [2026-08-11T15:17:11.446Z] create pull request in microsoft/vscode failed (attempt 1)
Original error: Validation Failed: {"resource":"PullRequest","code":"custom","field":"fork_collab","message":"fork_collab Fork collab can't be granted by someone without permission"} - https://docs.github.com/rest/pulls/pulls#create-a-pull-request
Retryable: false
Suggestion: This error cannot be resolved by retrying. Please check the error details and fix the underlying issue.
To create the pull request manually:
gh pr create --title "fix: treat persistent 404 from external ingest search as empty result (fixes #330268)" --base main --head vscodebot-pr:fix/external-ingest-persistent-404-8ef906b52b29e16a --repo microsoft/vscodeShow patch (37 lines)