Skip to content

fix(vscode): retry webview load on service worker failure#8514

Closed
markijbema wants to merge 3 commits into
mainfrom
mark/webview-sw-retry
Closed

fix(vscode): retry webview load on service worker failure#8514
markijbema wants to merge 3 commits into
mainfrom
mark/webview-sw-retry

Conversation

@markijbema
Copy link
Copy Markdown
Contributor

Summary

  • Mitigate VS Code platform bug (microsoft/vscode#125993) where the internal service worker fails to register, leaving all webviews blank with "Error loading webview: Could not register service worker: InvalidStateError"
  • After setting webview.html, an 8-second timer monitors for webviewReady. If it never arrives, re-assigns the HTML to force a fresh iframe + service worker registration attempt. Retries up to 3 times, then shows a "Reload Window" notification.
  • Covers all webview surfaces: sidebar, tab panels, Agent Manager, DiffViewer, SettingsEditor, and SubAgentViewer

Closes #8512

Mitigate VS Code platform bug (microsoft/vscode#125993) where the
internal service worker fails to register, leaving the webview blank.

After setting webview.html, start an 8s timer. If webviewReady never
arrives, re-assign the HTML to force a fresh iframe + service worker
registration. Retry up to 3 times, then show a 'Reload Window' prompt.

Covers sidebar, tab panels, Agent Manager, and DiffViewer.

Closes #8512
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 7, 2026

Code Review

Reviewer: AI (assisted by kilo-auto/free model)
Requested by: markijbema


Summary

This PR adds retry logic to handle VS Code's service worker registration failures (referenced issue: microsoft/vscode#125993). The fix is applied to three files: , , and .


Strengths

  1. Addresses a known VS Code bug - The referenced issue Webview Service Worker Error in registration due to invalid document state microsoft/vscode#125993 is a real platform issue, and this workaround is appropriate.
  2. Consistent implementation - The pattern is applied consistently across all three webview providers.
  3. User-friendly error handling - After max retries, shows a warning message with "Reload Window" action.
  4. Proper cleanup - is called in dispose methods to prevent timer leaks.
  5. Good constants - and are sensible defaults.

Issues to Address

  1. Duplicate code - The retry logic is duplicated across three files. Consider extracting to a shared utility class/trait.

  2. **** - is called but the method signature in accepts . The agent manager uses a different provider instance - need to verify this actually wires up correctly since there is , not .

  3. **Missing reset in ** - In , is set before , but in it relies on . Ensure this is properly reset when is called multiple times.

  4. Console.log vs proper logging - Uses // in but in . Should use consistent logging.

  5. No telemetry - Consider adding telemetry to track how often this retry mechanism triggers, to understand the scope of the VS Code bug.

  6. Race condition potential - If arrives just after starts but before it completes, the webview could be reloaded unnecessarily. Consider checking at the start of before mutating state.


Verdict

Approve with minor suggestions. The implementation is solid and handles the known VS Code issue well. The main concern is code duplication - a shared utility would be more maintainable. The wiring in should be verified to ensure the correct provider's is being called.

Copy link
Copy Markdown
Contributor

@kilo-code-bot kilo-code-bot Bot left a comment

Choose a reason for hiding this comment

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

Code Review — requested by @markijbema

Reviewed by: Kilo Code Agent (model: anthropic/claude-opus-4.6)


Summary

The core approach is sound — re-assigning webview.html to force a fresh iframe + service worker registration is the correct workaround per VS Code's own guidance. The linked issue (#8512) has excellent root cause analysis, and the upstream references are thorough. That said, there are several issues worth addressing before merge.


Issues

1. Code duplication — retry logic copy-pasted across two classes (High)

DiffViewerProvider and KiloProvider both implement identical retry machinery (scheduleReadyCheck, retryWebview, cancelReadyCheck, plus 5 instance/static properties). That's ~40 lines duplicated. This is clearly reusable (used in 3 surfaces) and should be extracted into a shared utility or mixin.

2. DiffViewerProvider.retryWebview() silently gives up — no user notification (Medium)

In KiloProvider, when retries are exhausted, the user sees a "Reload Window" warning notification. In DiffViewerProvider, it just logs to the output channel and stops. Users of the DiffViewer will see a blank panel with no indication of what happened or what to do. This should show the same notification.

3. scheduleReadyCheck is public on KiloProvider (Medium)

It's made public so VscodeHost can call it, but it exposes internal retry state management as public API. The html parameter accepting a closure that captures panel.webview also creates a subtle lifetime concern — if the panel is disposed between retry attempts, the closure still references the old webview. retryWebview checks !this.webview, but that's KiloProvider's own stored reference, not necessarily the one captured in the closure.

4. Race condition: retry timer fires during normal slow load (Medium)

8 seconds is a fixed timeout. On slow machines or under memory pressure (exactly the conditions that trigger this bug), a legitimate first load could exceed 8 seconds. The retry would blow away a webview that was about to become ready. Consider exponential backoff, or at least increasing the timeout on subsequent retries.

5. No tests (Medium)

This is reliability-critical retry logic with timers and multiple state transitions across 3 code paths. At minimum, unit tests should verify:

  • Timer is cancelled when "webviewReady" arrives
  • Retries increment and cap at MAX_RETRIES
  • dispose() cancels the timer
  • The notification appears after exhausting retries

6. ready flag coupling is fragile (Low)

DiffViewerProvider.wirePanel() sets this.ready = false before calling scheduleReadyCheck(), but scheduleReadyCheck() itself doesn't reset the ready flag. If scheduleReadyCheck were ever called without the caller resetting the flag first, retryWebview would immediately no-op. Same pattern exists in KiloProvider where isWebviewReady is reset by the caller, not by scheduleReadyCheck. If this gets extracted into a shared utility (per #1), the utility should own the reset.

7. Naming inconsistency: ready vs isWebviewReady (Low)

DiffViewerProvider uses this.ready, KiloProvider uses this.isWebviewReady. Makes the duplicated logic harder to follow and extract. Per the project style guide's single-word preference, ready is better — but consistency matters more.


What's good

  • Problem is well-documented with upstream issue references in every comment and log line
  • The workaround approach (re-assigning webview.html) is correct
  • Timer cleanup is properly handled in all dispose paths
  • The KiloProvider exhaustion path gives users a clear action ("Reload Window")
  • Clean integration into the existing wirePanel/resolveWebviewView/resolveWebviewPanel flows

Recommendation

Extract the retry logic into a shared utility, add the user notification to DiffViewerProvider, and add basic test coverage. The core approach is solid — this is mostly about reducing duplication and closing the gaps.

@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 7, 2026

Code Review (kilo/kilo-auto/balanced model)

Verdict: Request changes before merge

The fix correctly addresses VS Code service worker bug #125993, but there are maintainability concerns:


Critical Issues

1. Code duplication — The retry logic is copy-pasted nearly verbatim in DiffViewerProvider.ts:88-115 and KiloProvider.ts:2964-2995. Extract a shared WebviewRetryHelper class to avoid drift.

2. No test coverage — 118 lines of new retry logic with zero tests. This is high-risk code touching webview lifecycle and will be a regression surface.

3. Race condition — In KiloProvider.ts:486, cancelReadyCheck() is called after this.isWebviewReady = true. A late webviewReady message could theoretically slip through, though the isWebviewReady guard mitigates it.


Minor Issues

Issue Location
Naming inconsistency: ready vs isWebviewReady DiffViewerProvider vs KiloProvider
Logging inconsistency: this.log() vs console.warn/error DiffViewerProvider vs KiloProvider
Magic numbers: 8000ms / 3 retries hardcoded Both providers

What's Good

  • Clear bug documentation referencing microsoft/vscode#125993
  • Proper timer cleanup in dispose()
  • "Reload Window" notification UX is appropriate

kilo-code-bot Bot added 2 commits April 9, 2026 11:47
- add WebviewReadyRetry utility
- integrate into DiffViewerProvider, KiloProvider, and vscode-host
- replace legacy ready timer logic with the WebviewReadyRetry loader
- emit WEBVIEW_READY_RETRY and WEBVIEW_READY_FAILED telemetry events
- update telemetry types and add unit tests for webview-ready-retry
@markijbema markijbema closed this Apr 20, 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.

Webview fails to load: Could not register service worker (VS Code platform bug)

1 participant