fix: skip NES streamed edits for unknown target documents (fixes #326359)#326360
Open
vs-code-engineering[bot] wants to merge 1 commit into
Open
fix: skip NES streamed edits for unknown target documents (fixes #326359)#326360vs-code-engineering[bot] wants to merge 1 commit into
vs-code-engineering[bot] wants to merge 1 commit into
Conversation
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.
Summary
The Next Edit Suggestion (NES) path throws
BugIndicatingError("An unexpected bug occurred.") with high frequency — 468 users / 3,245 hits onGitHub.copilot-chat0.57.0(win32), plus ~920 more users across drifted sibling buckets (d5ee2c95,a0c33451,0be6ac5b,f5de1e2e).The crash originates in
createDocStateLookupMap(extensions/copilot/src/extension/inlineEdits/node/nextEditProvider.ts:148): when a streamed edit produced by the model targets a document that is neither one of the request's projected documents nor an edit-history entry, theCachedFunctionlookup falls through tothrow new BugIndicatingError(). The streamed edit'stargetDocumentis model output — an untrusted boundary — so an unrecognised document id is a normal runtime possibility, not a programming invariant violation, and must not be reported as an unexpected bug.The fix validates the model-produced
targetDocumentat the boundary (_rebaseAndCacheStreamedEdit) and skips unknown-document edits, returningundefined— a result both callers already handle gracefully as "edit could not be rebased".Fixes #326359
Recommended reviewer:
@alexr00Culprit Commit
The error is a genuinely new signature between
copilot-chat0.51.0(baseline, absent) and0.57.0(VS Code 1.129.0), per theerrors-regression-scancomment. The local checkout is a shallow (depth-1) clone, so per-line history before the checkout commit is not retrievable and an exact culprit SHA could not be confirmed offline.git blameattributes the currentcreateDocStateLookupMap/_rebaseAndCacheStreamedEditcode (including thethrow new BugIndicatingError()fall-through and thextabEditHistoryfallback loop) to recent work by Alex Ross (@alexr00). The regression coincides with the cross-file / streamed-edit rebase refactor that introduced thestatePerDoclookup map keyed by model-suppliedtargetDocumentids.Code Flow
flowchart TD A["getNextEdit"] --> B["_getNextEditCanThrow"] B --> C["fetchNextEdit"] C --> D["_executeNewNextEditRequest"] D --> E["editStream: model streams StreamedEdit (targetDocument is model-produced)"] E --> F["processEdit(streamedEdit)"] F --> G["_rebaseAndCacheStreamedEdit"] G --> H["statePerDoc.get(streamedEdit.targetDocument) cache.ts:117"] H --> I{"doc in projectedDocuments or xtabEditHistory?"} I -->|yes| J["return DocState"] I -->|no| K["throw new BugIndicatingError() nextEditProvider.ts:148"] K --> L["unhandled: 'An unexpected bug occurred.' -> error telemetry"]Affected Files
extensions/copilot/src/extension/inlineEdits/node/nextEditProvider.tstargetDocumentbefore thestatePerDoclookup; skip unknown-document streamed edits instead of throwing.Repro Steps
StreamedEditwhosetargetDocumentis not among the request's projected documents and not present as an'edit'entry inxtabEditHistory(e.g. a cross-file suggestion referencing a document that was not included in the request context)._rebaseAndCacheStreamedEditcallsstatePerDoc.get(streamedEdit.targetDocument), theCachedFunctionbody falls through both lookups and throwsBugIndicatingError, surfacing as the unhandled "An unexpected bug occurred." error.How the Fix Works
Chosen approach (
extensions/copilot/src/extension/inlineEdits/node/nextEditProvider.ts):createDocStateLookupMapnow returns{ statePerDoc, isKnownDocument }, whereisKnownDocument(id)reports — without throwing — whetherstatePerDoc.get(id)can resolve a document (present inprojectedDocuments, or an'edit'entry inxtabEditHistory). This reuses exactly the same membership logic the lookup body uses._rebaseAndCacheStreamedEditguards the model-producedstreamedEdit.targetDocumentwithisKnownDocument(...)before callingstatePerDoc.get(...). When the target is unknown it logs a trace and returnsundefined._executeNewNextEditRequestand_runSpeculativeProviderCall) already treat anundefinedresult as "edit could not be rebased" and skip it, so the streamed edit is dropped cleanly rather than crashing the stream.This is a guard clause placed at the model-output boundary — the point where untrusted data first enters the typed
DocumentId -> DocStatelookup — rather than at the crash site inside the cached function (fix at the data producer, not the crash site). The bypass site isnextEditProvider.ts:148, reached only via the model-suppliedtargetDocument; the guard sits at the sole producer path that can feed it an unvalidated id. Thethrow new BugIndicatingError()is deliberately left in place: it still correctly guards the internal invariant thatcurDocId(the active document, always a projected document) is resolvable, so a genuine internal misuse would still be reported. After this change,nextEditProvider.ts:776cannot forward an unknown model-producedtargetDocumentintostatePerDoc.get, because theisKnownDocumentguard returns early for exactly the ids that would otherwise reach the throw.Alternatives considered:
statePerDoc.get(...)call intry/catch— rejected because it hides the model-boundary condition behind exception handling and would also swallow genuine internal invariant violations, degrading telemetry instead of fixing the data path.CachedFunctionbody returnundefinedfor unknown ids — rejected becauseDocStateis consumed as non-nullable at several sites (e.g.statePerDoc.get(curDocId)), so weakening the map's contract would ripple null-checks across unrelated, always-valid call sites.Recommended Owner
@alexr00— Alex Ross authored the currentcreateDocStateLookupMap/_rebaseAndCacheStreamedEditstreamed-edit rebase code containing the crash site, and the regression tracks the cross-file streamed-edit refactor introduced between0.51.0and0.57.0.