wavetermdev/waveterm · error

error finding tab for block

Error message

error finding tab for block: %w

What it means

After fetching the block, BlockInfoCommand locates its containing tab with wstore.DBFindTabForBlockId. This error wraps failure of that search — the block exists but no tab referencing it could be found, or the lookup errored. It signals store inconsistency between the block and tab collections.

Solutions

  1. Retry the command after the deletion settles — the block is likely mid-removal.
  2. Treat orphaned blocks as inconsistent state: remove the block record or reload workspace state.
  3. Check the wrapped cause to distinguish NotFound (orphaned block) from a DB error.
  4. Refresh the client's workspace/tab data and re-request with a live blockId.

Example fix

// before
info, err := wshclient.BlockInfoCommand(ctx, blockId, nil) // tab already deleted
// after
if info, err := wshclient.BlockInfoCommand(ctx, blockId, nil); err != nil {
    blockId = pickLiveBlockIdFromTab(currentTabId) // choose a block whose tab still exists
}
_ = info
Defensive patterns

Strategy: fallback

Validate before calling

// prefer resolving tab directly instead of through a possibly-orphaned block
tabId := getTabIdForBlockFromLocalState(blockId)
if tabId == "" {
    return errors.New("block has no live tab; skip BlockInfoCommand")
}

Type guard

func isOrphanedBlock(err error) bool {
    return err != nil && strings.Contains(err.Error(), "error finding tab for block")
}

Try / catch

info, err := wshclient.BlockInfoCommand(ctx, blockId, nil)
if err != nil {
    if isOrphanedBlock(err) {
        // wait for deletion to settle, then retry once
        time.Sleep(200 * time.Millisecond)
        info, err = wshclient.BlockInfoCommand(ctx, blockId, nil)
    }
    if err != nil { return err }
}
_ = info

Prevention

When it happens

Trigger: Calling BlockInfoCommand for a blockId whose parent tab was deleted but whose block record lingers; DBFindTabForBlockId returns an internal store error; block id is valid but orphaned during a partial deletion.

Common situations: Interrupted block removal leaving orphaned block records; concurrent tab close while BlockInfoCommand runs; restored/migrated store files missing tab entries.

Related errors


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

Appendix: source

Thrown at pkg/wshrpc/wshserver/wshserver.go:813

	return &wshrpc.WaveFileInfo{
		ZoneId:    wf.ZoneId,
		Name:      wf.Name,
		Opts:      wf.Opts,
		CreatedTs: wf.CreatedTs,
		Size:      wf.Size,
		ModTs:     wf.ModTs,
		Meta:      wf.Meta,
	}
}

func (ws *WshServer) BlockInfoCommand(ctx context.Context, blockId string) (*wshrpc.BlockInfoData, error) {
	blockData, err := wstore.DBMustGet[*waveobj.Block](ctx, blockId)
	if err != nil {
		return nil, fmt.Errorf("error getting block: %w", err)
	}
	tabId, err := wstore.DBFindTabForBlockId(ctx, blockId)
	if err != nil {
		return nil, fmt.Errorf("error finding tab for block: %w", err)
	}
	workspaceId, err := wstore.DBFindWorkspaceForTabId(ctx, tabId)
	if err != nil {
		return nil, fmt.Errorf("error finding window for tab: %w", err)
	}
	fileList, err := filestore.WFS.ListFiles(ctx, blockId)
	if err != nil {
		return nil, fmt.Errorf("error listing blockfiles: %w", err)
	}
	var fileInfoList []*wshrpc.WaveFileInfo
	for _, wf := range fileList {
		fileInfoList = append(fileInfoList, waveFileToWaveFileInfo(wf))
	}
	return &wshrpc.BlockInfoData{
		BlockId:     blockId,
		TabId:       tabId,
		WorkspaceId: workspaceId,
		Block:       blockData,

View on GitHub (pinned to a4447c1563)