wavetermdev/waveterm · error
unable to get layout id for given tab id %s: %w
Error message
unable to get layout id for given tab id %s: %w
What it means
GetLayoutIdForTab loads the Tab and returns its LayoutState id. If the DBGet itself errors (storage failure, not a nil tab) it wraps it as "unable to get layout id for given tab id %s: %w". It identifies which tab id the caller supplied so the layout action queue can report a precise failure.
Source
Thrown at pkg/wcore/layout.go:77
}},
}
}
func GetNewTabLayout() PortableLayout {
return PortableLayout{
{IndexArr: []int{0}, BlockDef: &waveobj.BlockDef{
Meta: waveobj.MetaMapType{
waveobj.MetaKey_View: "term",
waveobj.MetaKey_Controller: "shell",
},
}, Focused: true},
}
}
func GetLayoutIdForTab(ctx context.Context, tabId string) (string, error) {
tabObj, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)
if err != nil {
return "", fmt.Errorf("unable to get layout id for given tab id %s: %w", tabId, err)
}
return tabObj.LayoutState, nil
}
func QueueLayoutAction(ctx context.Context, layoutStateId string, actions ...waveobj.LayoutActionData) error {
layoutStateObj, err := wstore.DBGet[*waveobj.LayoutState](ctx, layoutStateId)
if err != nil {
return fmt.Errorf("unable to get layout state for given id %s: %w", layoutStateId, err)
}
for i := range actions {
if actions[i].ActionId == "" {
actions[i].ActionId = uuid.New().String()
}
}
if layoutStateObj.PendingBackendActions == nil {
layoutStateObj.PendingBackendActions = &actionsView on GitHub (pinned to a4447c1563)
Solutions
- Verify the id is a valid tab OID (check its OType / prefix).
- Re-fetch the current tab list and use a live tab id.
- Inspect the wrapped cause for store/IO issues and retry after recovery.
- Use DBGet[*waveobj.Tab] directly first as a pre-check if unsure.
Example fix
// before
layoutId, err := wcore.GetLayoutIdForTab(ctx, someId) // someId is a workspace id
// after
tab, _ := wstore.DBGet[*waveobj.Tab](ctx, someId)
if tab == nil {
return fmt.Errorf("not a tab: %s", someId)
}
layoutId, err := wcore.GetLayoutIdForTab(ctx, someId) Defensive patterns
Strategy: validation
Validate before calling
oref, err := waveobj.ParseORef(tabId)
if err != nil || oref.OType != waveobj.OType_Tab {
return fmt.Errorf("id %s is not a tab", tabId)
} Type guard
func isTabId(id string) bool {
oref := waveobj.ParseORefNoErr(id)
return oref != nil && oref.OType == waveobj.OType_Tab
} Try / catch
layoutId, err := wcore.GetLayoutIdForTab(ctx, tabId)
if err != nil {
log.Printf("layout lookup failed for tab %s: %v", tabId, err)
return err
} Prevention
- Confirm the id's OType is Tab before calling layout APIs.
- Refresh tab references after tab-close events.
- Pre-check with DBGet[*waveobj.Tab] when the id's origin is uncertain.
When it happens
Trigger: Calling GetLayoutIdForTab (directly or via QueueLayoutActionForTab) with a tab id whose DBGet fails: store read error, invalid OID format rejected by the update layer, or decode failure of the tab row.
Common situations: Passing a layout id or workspace id instead of a tab id; querying a tab after it was deleted; corrupted tab record in the local store.
Related errors
- error getting block: %w
- error deleting subblock %s: %w
- error deleting block: %w
- error finding workspace for tab to delete %s: %w
- error deleting tab %s: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/e16ebe72218bc29f.
Report an issue: GitHub.