{"record":{"id":"59dd212060ac68f1","repo":"wavetermdev/waveterm","slug":"block-not-found-in-tab-blockid","errorCode":null,"errorMessage":"Block not found in tab: ${blockId}","messagePattern":"Block not found in tab: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/app/store/tabrpcclient.ts","lineNumber":103,"sourceCode":"\n        if (data.text) {\n            model.appendText(data.text);\n        }\n\n        if (data.submit) {\n            await model.handleSubmit();\n        }\n    }\n\n    async handle_setblockfocus(rh: RpcResponseHelper, blockId: string): Promise<void> {\n        const layoutModel = getLayoutModelForStaticTab();\n        if (!layoutModel) {\n            throw new Error(\"Layout model not found\");\n        }\n\n        const node = layoutModel.getNodeByBlockId(blockId);\n        if (!node) {\n            throw new Error(`Block not found in tab: ${blockId}`);\n        }\n\n        layoutModel.focusNode(node.id);\n    }\n\n    async handle_getfocusedblockdata(rh: RpcResponseHelper): Promise<FocusedBlockData> {\n        const layoutModel = getLayoutModelForStaticTab();\n        if (!layoutModel) {\n            throw new Error(\"Layout model not found\");\n        }\n\n        const focusedNode = globalStore.get(layoutModel.focusedNode);\n        const blockId = focusedNode?.data?.blockId;\n\n        if (!blockId) {\n            return null;\n        }\n","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/frontend/app/store/tabrpcclient.ts#L85-L121","documentation":"handle_setblockfocus located the tab's LayoutModel but getNodeByBlockId(blockId) returned null, so the block with that id is not present in this tab. The focus operation only applies to blocks within the receiving tab's layout tree.","triggerScenarios":"Focusing a blockId that was closed, belongs to a different tab, or never existed in the receiving tab; stale blockId from persisted state after workspace restore.","commonSituations":"Multi-tab UIs sending focus commands via the wrong tab's client; hot-reload/dev scenarios where ids regenerated; automation replaying old block ids after user closed blocks.","solutions":["Confirm the block exists in the target tab before focusing (query node map or focused block data)","Route the RPC through the owning tab's TabRpcClient","Purge or re-map blockIds on tab/workspace restore events","Guard UI code that auto-focuses blocks on close/delete events"],"exampleFix":"// before\nawait rpcService.call(\"setblockfocus\", [blockId]);\n// after\nconst node = layoutModel?.getNodeByBlockId(blockId);\nif (node) {\n    await rpcService.call(\"setblockfocus\", [blockId]);\n} else {\n    console.warn(\"skip focus, block gone:\", blockId);\n}","handlingStrategy":"validation","validationCode":"if (getLayoutModelForStaticTab()?.getNodeByBlockId(blockId) == null) {\n    console.warn(\"block not focusable in this tab:\", blockId);\n    return;\n}","typeGuard":"function isFocusableBlock(blockId: string): boolean {\n    return getLayoutModelForStaticTab()?.getNodeByBlockId(blockId) != null;\n}","tryCatchPattern":"try {\n    await rpcService.call(\"setblockfocus\", [blockId]);\n} catch (e) {\n    if (String(e).startsWith(\"Block not found in tab:\")) {\n        focusFirstAvailableBlock();\n    } else {\n        throw e;\n    }\n}","preventionTips":["Re-map persisted blockIds after workspace/tab restore","Send focus commands only to the tab owning the block","Clean up focus requests when blocks are closed"],"tags":["focus","invalid-argument","frontend"],"backgroundTag":"block-id-not-found","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}