wavetermdev/waveterm · warning
no webcontents found with blockid ${data.blockid}
Error message
no webcontents found with blockid ${data.blockid} What it means
WslConn.Close waits for any in-flight waiter (a registered goroutine performing connection work) to finish before closing. It polls conn.HasWaiter every 10ms and, if the waiter is still registered after 2 seconds, returns this timeout error instead of closing while work is in progress. Reaching this error means the close was refused, not that the connection failed.
Source
Thrown at emain/emain-wsh.ts:28
import { getWebContentsByBlockId, webGetSelector } from "./emain-web";
import { createBrowserWindow, getWaveWindowById, getWaveWindowByWorkspaceId } from "./emain-window";
export class ElectronWshClientType extends WshClient {
constructor() {
super("electron");
}
async handle_webselector(rh: RpcResponseHelper, data: CommandWebSelectorData): Promise<string[]> {
if (!data.tabid || !data.blockid || !data.workspaceid) {
throw new Error("tabid and blockid are required");
}
const ww = getWaveWindowByWorkspaceId(data.workspaceid);
if (ww == null) {
throw new Error(`no window found with workspace ${data.workspaceid}`);
}
const wc = await getWebContentsByBlockId(ww, data.tabid, data.blockid);
if (wc == null) {
throw new Error(`no webcontents found with blockid ${data.blockid}`);
}
const rtn = await webGetSelector(wc, data.selector, data.opts);
return rtn;
}
async handle_notify(rh: RpcResponseHelper, notificationOptions: WaveNotificationOptions) {
new Notification({
title: notificationOptions.title,
body: notificationOptions.body,
silent: notificationOptions.silent,
}).show();
}
async handle_getupdatechannel(rh: RpcResponseHelper): Promise<string> {
return getResolvedUpdateChannel();
}
async handle_focuswindow(rh: RpcResponseHelper, windowId: string) {View on GitHub (pinned to a4447c1563)
Solutions
- Wait a moment and retry the Close/Reconnect — the in-flight waiter usually completes
- Investigate what is holding HasWaiter (connserver startup, version check) and why it exceeds 2s
- If the waiter is permanently stuck, restart the Wave connection/block to clear state
- Retry with backoff rather than immediately reconnecting after a status change
Example fix
// before
err := conn.Reconnect(ctx) // can hit waiter timeout during handshake
// after
if err := conn.Reconnect(ctx); err != nil && strings.Contains(err.Error(), "timeout waiting for waiter") {
time.Sleep(3 * time.Second)
err = conn.Reconnect(ctx) // retry after in-flight work settles
} Defensive patterns
Strategy: retry
Validate before calling
if conn.HasWaiter.Load() {
time.Sleep(3 * time.Second) // let in-flight work finish before closing
} Try / catch
err := conn.Reconnect(ctx)
if err != nil && strings.Contains(err.Error(), "timeout waiting for waiter") {
time.Sleep(3 * time.Second)
err = conn.Reconnect(ctx) // retry with backoff
} Prevention
- Add backoff between reconnect attempts after connection drops
- Avoid calling Close/Reconnect while another connection operation is known to be running
- Track connection state changes so reconnects are not fired during handshakes
When it happens
Trigger: Reconnect (or direct Close) is called while another operation holds the waiter flag for over 2 seconds — e.g. a long-running connserver startup or handshake still in flight.
Common situations: Reconnect attempted immediately after a network drop while the connection was still handshaking; slow WSL startup exceeding the 2s window; a waiter goroutine stuck/hung.
Related errors
- error getting wave file: + resp.statusText
- unable to obtain client info: %w
- timeout waiting for connserver to register
- context timeout
- cannot connect to %q when status is %q
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/e6e3c9253bae83f9.
Report an issue: GitHub.