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
- Retry the command after the deletion settles — the block is likely mid-removal.
- Treat orphaned blocks as inconsistent state: remove the block record or reload workspace state.
- Check the wrapped cause to distinguish NotFound (orphaned block) from a DB error.
- 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
- Delete block records together with their parent tab atomically
- Retry briefly to ride out concurrent tab-close races
- Detect orphaned blocks and trigger store cleanup
- Resolve tab ids from live workspace state when possible
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
- error finding tab: %v
- error getting block: %w
- error finding window for tab: %w
- object reference is not a block
- delete block failed: %v
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/91cee30277590434.
Report an issue: GitHub.