wavetermdev/waveterm · error

error finding tab for block: %w

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.

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)

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.