wavetermdev/waveterm · error
error getting all windows: %w
Error message
error getting all windows: %w
What it means
SwitchWorkspace enumerates all Window objects with wstore.DBGetAllObjsByType to enforce that one workspace is owned by at most one window. This error wraps a failure of that enumeration (DB read error), preventing the switch from proceeding even though both the workspace and window were found.
Source
Thrown at pkg/wcore/window.go:38
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
}
}
window.WorkspaceId = workspaceId
err = wstore.DBUpdate(ctx, window)
if err != nil {
return nil, fmt.Errorf("error updating window: %w", err)
}
deleted, _, err := DeleteWorkspace(ctx, curWsId, false)
if err != nil && deleted {View on GitHub (pinned to a4447c1563)
Solutions
- Check the wrapped cause for 'database is locked' and close other Wave processes holding the DB
- Fix underlying storage problems (disk full, permissions, I/O errors) indicated by the wrapped error
- Retry the switch after transient DB errors; the operation is read-mostly and idempotent until the update step
- If wave.db is corrupt, back it up and remove it (windows/workspaces will be recreated)
Example fix
// caller-side retry
var ws *waveobj.Workspace
err := retry(3, func() error {
var e error
ws, e = wcore.SwitchWorkspace(ctx, winId, wsId)
return e
}) Defensive patterns
Strategy: retry
Validate before calling
// check DB reachable before batch operations
if err := wstore.DBGetAllObjsByType[*waveobj.Window](ctx, waveobj.OType_Window); err != nil {
log.Printf("window enumeration unhealthy: %v", err)
} Try / catch
err := wcore.SwitchWorkspace(ctx, winId, wsId)
for i := 0; err != nil && strings.Contains(err.Error(), "getting all windows") && i < 3; i++ {
time.Sleep(300 * time.Millisecond)
err = wcore.SwitchWorkspace(ctx, winId, wsId)
} Prevention
- Run a single app process per wave.db to avoid lock contention
- Keep adequate disk space and healthy storage I/O
- Use contexts with generous timeouts for DB-heavy operations
- Monitor and alert on SQLite lock/corruption errors in logs
When it happens
Trigger: wstore.DBGetAllObjsByType[*waveobj.Window](ctx, waveobj.OType_Window) returns an error during SwitchWorkspace — SQLite read failure, DB locked by another process, corruption, or the 5s-style context deadline expiring during the query.
Common situations: Concurrent Wave client processes contending for the DB; disk I/O errors; large/corrupt wave.db; storage pressure making reads slow enough to hit the context timeout.
Related errors
- error getting window: %w
- error creating window: %w
- error getting window: %w
- error getting client: %v
- error getting block: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/604ec96831c9693a.
Report an issue: GitHub.