wavetermdev/waveterm · error

error getting workspace: %w

Error message

error getting workspace: %w

What it means

CreateWindow with a non-empty workspaceId looks up the target workspace via GetWorkspace; this error wraps the lookup failure. GetWorkspace uses DBMustGet, so a missing OID is itself an error here, not a nil result.

Source

Thrown at pkg/wcore/window.go:93

		log.Printf("error getting window %q: %v\n", windowId, err)
		return nil, err
	}
	return window, nil
}

func CreateWindow(ctx context.Context, winSize *waveobj.WinSize, workspaceId string) (*waveobj.Window, error) {
	log.Printf("CreateWindow %v %v\n", winSize, workspaceId)
	var ws *waveobj.Workspace
	if workspaceId == "" {
		ws1, err := CreateWorkspace(ctx, "", "", "", false, false)
		if err != nil {
			return nil, fmt.Errorf("error creating workspace: %w", err)
		}
		ws = ws1
	} else {
		ws1, err := GetWorkspace(ctx, workspaceId)
		if err != nil {
			return nil, fmt.Errorf("error getting workspace: %w", err)
		}
		ws = ws1
	}
	windowId := uuid.NewString()
	if winSize == nil {
		winSize = &waveobj.WinSize{
			Width:  0,
			Height: 0,
		}
	}
	window := &waveobj.Window{
		OID:         windowId,
		WorkspaceId: ws.OID,
		IsNew:       true,
		Pos: waveobj.Point{
			X: 0,
			Y: 0,
		},

View on GitHub (pinned to a4447c1563)

Solutions

  1. Validate the workspaceId exists before calling CreateWindow (fetch workspace list first)
  2. Pass "" for workspaceId to let CreateWindow make a fresh workspace instead
  3. Check the wrapped %w error for 'not found' vs I/O failure
  4. Refresh any cached workspace IDs after workspaces are deleted

Example fix

// before
win, err := wcore.CreateWindow(ctx, nil, staleWorkspaceId)
// after
wsList, err := wstore.DBGetAllObjsByType[*waveobj.Workspace](ctx, waveobj.OType_Workspace)
if err != nil {
	return err
}
var wsId string
for _, ws := range wsList {
	if ws.OID == staleWorkspaceId {
		wsId = staleWorkspaceId
		break
	}
}
win, err := wcore.CreateWindow(ctx, nil, wsId) // "" if not found -> creates new workspace
Defensive patterns

Strategy: validation

Validate before calling

func workspaceExists(ctx context.Context, wsId string) bool {
	if wsId == "" {
		return true // CreateWindow will make a new one
	}
	_, err := wcore.GetWorkspace(ctx, wsId)
	return err == nil
}

Type guard

func hasWorkspaceId(workspaceId string) bool {
	_, err := uuid.Parse(workspaceId)
	return err == nil
}

Try / catch

win, err := wcore.CreateWindow(ctx, winSize, workspaceId)
if err != nil && strings.Contains(err.Error(), "error getting workspace") {
	log.Printf("workspace %s gone, falling back to new workspace", workspaceId)
	win, err = wcore.CreateWindow(ctx, winSize, "")
}

Prevention

When it happens

Trigger: wcore.CreateWindow(ctx, winSize, workspaceId) where workspaceId is non-empty and GetWorkspace fails — typically the workspace OID does not exist in wstore (deleted by another client) or the DB read fails.

Common situations: Caller passes a stale workspaceId saved from a previous session; workspace was deleted when its last window closed (CloseWindow auto-deletes empty workspaces); typo'd or malformed UUID; DB read error.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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