{"record":{"id":"e16ebe72218bc29f","repo":"wavetermdev/waveterm","slug":"unable-to-get-layout-id-for-given-tab-id-s-w","errorCode":null,"errorMessage":"unable to get layout id for given tab id %s: %w","messagePattern":"unable to get layout id for given tab id (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/wcore/layout.go","lineNumber":77,"sourceCode":"\t\t}},\n\t}\n}\n\nfunc GetNewTabLayout() PortableLayout {\n\treturn PortableLayout{\n\t\t{IndexArr: []int{0}, BlockDef: &waveobj.BlockDef{\n\t\t\tMeta: waveobj.MetaMapType{\n\t\t\t\twaveobj.MetaKey_View:       \"term\",\n\t\t\t\twaveobj.MetaKey_Controller: \"shell\",\n\t\t\t},\n\t\t}, Focused: true},\n\t}\n}\n\nfunc GetLayoutIdForTab(ctx context.Context, tabId string) (string, error) {\n\ttabObj, err := wstore.DBGet[*waveobj.Tab](ctx, tabId)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to get layout id for given tab id %s: %w\", tabId, err)\n\t}\n\treturn tabObj.LayoutState, nil\n}\n\nfunc QueueLayoutAction(ctx context.Context, layoutStateId string, actions ...waveobj.LayoutActionData) error {\n\tlayoutStateObj, err := wstore.DBGet[*waveobj.LayoutState](ctx, layoutStateId)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to get layout state for given id %s: %w\", layoutStateId, err)\n\t}\n\n\tfor i := range actions {\n\t\tif actions[i].ActionId == \"\" {\n\t\t\tactions[i].ActionId = uuid.New().String()\n\t\t}\n\t}\n\n\tif layoutStateObj.PendingBackendActions == nil {\n\t\tlayoutStateObj.PendingBackendActions = &actions","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/wcore/layout.go#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlayoutId, err := wcore.GetLayoutIdForTab(ctx, someId) // someId is a workspace id\n// after\ntab, _ := wstore.DBGet[*waveobj.Tab](ctx, someId)\nif tab == nil {\n    return fmt.Errorf(\"not a tab: %s\", someId)\n}\nlayoutId, err := wcore.GetLayoutIdForTab(ctx, someId)","handlingStrategy":"validation","validationCode":"oref, err := waveobj.ParseORef(tabId)\nif err != nil || oref.OType != waveobj.OType_Tab {\n    return fmt.Errorf(\"id %s is not a tab\", tabId)\n}","typeGuard":"func isTabId(id string) bool {\n    oref := waveobj.ParseORefNoErr(id)\n    return oref != nil && oref.OType == waveobj.OType_Tab\n}","tryCatchPattern":"layoutId, err := wcore.GetLayoutIdForTab(ctx, tabId)\nif err != nil {\n    log.Printf(\"layout lookup failed for tab %s: %v\", tabId, err)\n    return err\n}","preventionTips":["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."],"tags":["wave-terminal","layout","tab-lookup","database-read","wrapped-error"],"backgroundTag":"database-read-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}