wavetermdev/waveterm · error
error getting window: %w
Error message
error getting window: %w
What it means
SwitchWorkspace loads the window with GetWindow after validating the target workspace. This error wraps a failed window lookup — the windowId does not match an existing Window object or the DB read failed. No workspace switch occurs.
Source
Thrown at pkg/wcore/window.go:29
"github.com/google/uuid"
"github.com/wavetermdev/waveterm/pkg/eventbus"
"github.com/wavetermdev/waveterm/pkg/util/utilfn"
"github.com/wavetermdev/waveterm/pkg/waveobj"
"github.com/wavetermdev/waveterm/pkg/wshrpc"
"github.com/wavetermdev/waveterm/pkg/wshrpc/wshclient"
"github.com/wavetermdev/waveterm/pkg/wshutil"
"github.com/wavetermdev/waveterm/pkg/wstore"
)
func SwitchWorkspace(ctx context.Context, windowId string, workspaceId string) (*waveobj.Workspace, error) {
log.Printf("SwitchWorkspace %s %s\n", windowId, workspaceId)
ws, err := GetWorkspace(ctx, workspaceId)
if err != nil {
return nil, fmt.Errorf("error getting new workspace: %w", err)
}
window, err := GetWindow(ctx, windowId)
if err != nil {
return nil, fmt.Errorf("error getting window: %w", err)
}
curWsId := window.WorkspaceId
if curWsId == workspaceId {
return nil, nil
}
allWindows, err := wstore.DBGetAllObjsByType[*waveobj.Window](ctx, waveobj.OType_Window)
if err != nil {
return nil, fmt.Errorf("error getting all windows: %w", err)
}
for _, w := range allWindows {
if w.WorkspaceId == workspaceId {
log.Printf("workspace %s already has a window %s, focusing that window\n", workspaceId, w.OID)
client := wshclient.GetBareRpcClient()
err = wshclient.FocusWindowCommand(client, w.OID, &wshrpc.RpcOpts{Route: wshutil.ElectronRoute})
return nil, err
}View on GitHub (pinned to a4447c1563)
Solutions
- Confirm the window still exists before switching (re-fetch the window list and re-check the ID)
- Use a valid, current window OID from wstore (OType_Window) rather than a cached value
- In the caller, treat not-found as benign: skip the switch or create a new window for the workspace
- If the wrapped error is a DB error rather than not-found, investigate database health
Example fix
// before
ws, err := wcore.SwitchWorkspace(ctx, staleWinId, wsId)
// after
win, err := wcore.GetWindow(ctx, winId)
if errors.Is(err, wstore.ErrNotFound) {
win, err = wcore.CreateWindow(ctx, wsId) // create instead of failing
} Defensive patterns
Strategy: validation
Validate before calling
_, err := wcore.GetWindow(ctx, windowId)
if err != nil {
return fmt.Errorf("window %s unavailable: %w", windowId, err)
} Type guard
func windowExists(ctx context.Context, id string) bool {
_, err := wcore.GetWindow(ctx, id)
return err == nil
} Try / catch
ws, err := wcore.SwitchWorkspace(ctx, winId, wsId)
if err != nil && strings.Contains(err.Error(), "getting window") {
// window is gone; create one for the target workspace
ws, err = wcore.CreateWindowForWorkspace(ctx, wsId)
} Prevention
- Subscribe to window-close events and drop stale windowIds
- Validate the window exists immediately before switching
- Handle races with window close by re-fetching instead of failing
- Ensure windowIds come from the current store, not persisted caches
When it happens
Trigger: Calling SwitchWorkspace(ctx, windowId, workspaceId) with a windowId that no longer exists (window closed), a malformed/non-UUID windowId, or an underlying DB read error from GetWindow.
Common situations: RPC from the frontend racing a window close; stale windowId cached in a client after the window was deleted; startup code running before windows are registered in the store.
Related errors
- error getting new workspace: %w
- error getting window: %w
- error getting all windows: %w
- %s: no such file
- secret not found: %s
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/e319d252abad6330.
Report an issue: GitHub.