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

  1. Check the wrapped cause for 'database is locked' and close other Wave processes holding the DB
  2. Fix underlying storage problems (disk full, permissions, I/O errors) indicated by the wrapped error
  3. Retry the switch after transient DB errors; the operation is read-mostly and idempotent until the update step
  4. 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

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


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/604ec96831c9693a. Report an issue: GitHub.