wavetermdev/waveterm · error

error closing tab: %w

Error message

error closing tab: %w

What it means

CloseTab deletes the tab via wcore.DeleteTab(ctx, workspaceId, tabId, true) and computes the next active tab. If deletion fails, the error is wrapped as "error closing tab: %w" and CloseTabRtn is left nil. The wrapping preserves the wcore-level cause (not found, DB error, etc.).

Source

Thrown at pkg/service/workspaceservice/workspaceservice.go:230

		ArgNames:   []string{"ctx", "workspaceId", "tabId", "fromElectron"},
		ReturnDesc: "CloseTabRtn",
	}
}

// returns the new active tabid
func (svc *WorkspaceService) CloseTab(ctx context.Context, workspaceId string, tabId string, fromElectron bool) (*CloseTabRtnType, waveobj.UpdatesRtnType, error) {
	ctx = waveobj.ContextWithUpdates(ctx)
	tab, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)
	if err == nil && tab != nil {
		go func() {
			for _, blockId := range tab.BlockIds {
				blockcontroller.DestroyBlockController(blockId)
			}
		}()
	}
	newActiveTabId, err := wcore.DeleteTab(ctx, workspaceId, tabId, true)
	if err != nil {
		return nil, nil, fmt.Errorf("error closing tab: %w", err)
	}
	rtn := &CloseTabRtnType{}
	if newActiveTabId == "" {
		rtn.CloseWindow = true
	} else {
		rtn.NewActiveTabId = newActiveTabId
	}
	updates := waveobj.ContextGetUpdatesRtn(ctx)
	go func() {
		defer func() {
			panichandler.PanicHandler("WorkspaceService:CloseTab:SendUpdateEvents", recover())
		}()
		wps.Broker.SendUpdateEvents(updates)
	}()
	return rtn, updates, nil
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Confirm the tabId still exists in the workspace before calling CloseTab
  2. Unwrap the error to see wcore.DeleteTab's root cause
  3. Refresh the workspace view in the client to drop stale tab references
  4. Check DB health/writability

Example fix

// before
wsSvc.CloseTab(wsId, tabId) // may fail if already closed
// after
tab, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)
if err != nil { return nil } // tab already gone
wsSvc.CloseTab(wsId, tabId)
Defensive patterns

Strategy: validation

Validate before calling

tab, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)
if err != nil {
    return nil // already closed; nothing to do
}
_, _, err = svc.CloseTab(workspaceId, tabId)

Try / catch

_, _, err := svc.CloseTab(workspaceId, tabId)
if err != nil {
    if errors.Is(errors.Unwrap(err), waveobj.ErrNotFound) { return nil } // treat as success
    return err
}

Prevention

When it happens

Trigger: Calling CloseTab(workspaceId, tabId) with a tabId not present in the workspace, a nonexistent workspaceId, or a wcore.DeleteTab storage failure.

Common situations: User closing a tab that was already closed in another window; stale frontend state; DB write failure during delete.

Related errors


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