Skip to content

fix: CodeLens registration leak, cancellation surfaced as error, LanguageModelError codes missing from messages#3

Merged
moonolgerd merged 2 commits intofix/analysis-investigationfrom
copilot/sub-pr-2
Mar 7, 2026
Merged

fix: CodeLens registration leak, cancellation surfaced as error, LanguageModelError codes missing from messages#3
moonolgerd merged 2 commits intofix/analysis-investigationfrom
copilot/sub-pr-2

Conversation

Copy link

Copilot AI commented Mar 7, 2026

Three robustness issues in the CodeLens registration lifecycle and Copilot error handling, surfaced by PR review.

Changes

extension.ts — CodeLens provider registration leak

Initial registerCodeLensProviders call pushed disposables directly into context.subscriptions, bypassing languageRegistrations. On sourceDoc.languages config change, only the subsequent registrations were disposed — the initial set survived indefinitely, and re-registrations accumulated duplicates.

Now all registrations (initial and subsequent) are tracked exclusively in languageRegistrations. A single wrapper disposable handles deactivation cleanup via context.subscriptions:

let languageRegistrations: vscode.Disposable[] = [];
registerCodeLensProviders(codeLensProvider, languageRegistrations);
context.subscriptions.push({ dispose: () => languageRegistrations.forEach(d => d.dispose()) });

explanationProvider.ts — Cancellation surfaced as empty-response error

If the cancellation token fired mid-stream before any chunks arrived, result stayed empty and the !result guard threw a user-visible error. Added an explicit cancellation check before the empty-response guard:

if (token.isCancellationRequested) { throw new vscode.CancellationError(); }
if (!result) { throw new Error('Copilot returned an empty explanation. Please try again.'); }

explanationProvider.tsLanguageModelError code absent from messages

Specific LanguageModelError cases (NoPermissions, Blocked, NotFound, RequestFailed) omitted err.code from their messages, unlike the default case. All cases now include the code for debuggability:

throw new Error(`Copilot error (${err.code}): access denied. Please check your GitHub Copilot subscription.`);

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…rror codes

Co-authored-by: moonolgerd <3743184+moonolgerd@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix analysis error investigation issues in Source Doc extension fix: CodeLens registration leak, cancellation surfaced as error, LanguageModelError codes missing from messages Mar 7, 2026
@moonolgerd moonolgerd marked this pull request as ready for review March 7, 2026 05:57
Copilot AI review requested due to automatic review settings March 7, 2026 05:57
@moonolgerd moonolgerd merged commit 8577a8a into fix/analysis-investigation Mar 7, 2026
1 check passed
@moonolgerd moonolgerd deleted the copilot/sub-pr-2 branch March 7, 2026 05:57
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes three robustness bugs in the extension's CodeLens provider lifecycle and Copilot error handling.

Changes:

  • extension.ts: Fixes a CodeLens provider registration leak where the initial registerCodeLensProviders() call was bypassing the languageRegistrations tracking array, causing initial registrations to survive extension deactivation and accumulate duplicates on config changes. The fix tracks all registrations in languageRegistrations and uses a closure-capturing wrapper disposable for deactivation cleanup.
  • explanationProvider.ts: Fixes cancellation being surfaced as an empty-response error (by adding a token.isCancellationRequested check after streaming), and adds err.code to LanguageModelError messages for all specific cases (NoPermissions, Blocked, NotFound, RequestFailed) to match the existing default case.
  • package-lock.json: Version bump from 0.2.1 to 0.3.0 to reflect accumulated fixes.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/extension.ts Fixes registration leak by removing context parameter from registerCodeLensProviders and tracking all registrations in languageRegistrations with a wrapper disposable
src/explanationProvider.ts Adds cancellation check after streaming and includes err.code in all LanguageModelError messages
package-lock.json Version bump from 0.2.1 to 0.3.0

Comment on lines +96 to +98
if (token.isCancellationRequested) {
throw new vscode.CancellationError();
}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The new cancellation check (lines 96-98) handles two sub-scenarios: (1) token cancelled before any chunks arrive (result is empty), and (2) token cancelled mid-stream after some chunks have already been accumulated (result is non-empty). The existing test at line 176 only covers the first sub-scenario. The second sub-scenario — where chunks have been partially received before cancellation — is the key case that this PR was introduced to fix (previously it would have thrown the empty-response error only if result was empty), but it has no dedicated test to verify that partial content is discarded and CancellationError is thrown. Adding a test with a fake model that yields chunks and a token cancelled after the first chunk would verify the intended fix.

Copilot uses AI. Check for mistakes.

result = result.trim();
if (token.isCancellationRequested) {
throw new vscode.CancellationError();
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

The new CancellationError thrown when token.isCancellationRequested is true after streaming (line 96-98) propagates to callers that do not specifically handle it. In runExplain (extension.ts ~line 310), the generic catch (err) block catches the CancellationError and shows a user-visible error message like "Source Doc: Canceled". In explainFile, the cancellation errors accumulate in the results array and cause a misleading "N line(s) failed" error message to appear at the end.

The callers already guard against cancellation (the if (!token.isCancellationRequested) checks after explain() returns), but they don't guard against CancellationError being thrown. The fix should either check for err instanceof vscode.CancellationError in both catch blocks and silently swallow it, or re-check token.isCancellationRequested in the callers' catch blocks before showing the error.

Suggested change
throw new vscode.CancellationError();
// Let callers handle cancellation via the token rather than an exception.
// Do not cache partial results or surface an "empty explanation" error.
return result;

Copilot uses AI. Check for mistakes.
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.

3 participants