{"record":{"id":"470508cc381fac23","repo":"wavetermdev/waveterm","slug":"display-container-not-found","errorCode":null,"errorMessage":"Display container not found","messagePattern":"Display container not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/app/store/tabrpcclient.ts","lineNumber":35,"sourceCode":"\n    handle_captureblockscreenshot(rh: RpcResponseHelper, data: CommandCaptureBlockScreenshotData): Promise<string> {\n        return this.captureBlockScreenshot(data.blockid);\n    }\n\n    async captureBlockScreenshot(blockId: string): Promise<string> {\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: ${blockId}`);\n        }\n\n        const displayContainer = layoutModel.displayContainerRef.current;\n        if (!displayContainer) {\n            throw new Error(\"Display container not found\");\n        }\n\n        const containerRect = displayContainer.getBoundingClientRect();\n        const additionalProps = layoutModel.getNodeAdditionalProperties(node);\n\n        let electronRect: Electron.Rectangle;\n\n        if (!additionalProps?.rect) {\n            // Bug: rect is not set when there is only one block in the layout\n            // In this case, use the full container rect\n            electronRect = {\n                x: Math.round(containerRect.x),\n                y: Math.round(containerRect.y),\n                width: Math.round(containerRect.width),\n                height: Math.round(containerRect.height),\n            };\n        } else {\n            const blockRect = additionalProps.rect;","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/frontend/app/store/tabrpcclient.ts#L17-L53","documentation":"captureBlockScreenshot found the layout node for the block, but the LayoutModel's displayContainerRef.current is null — the DOM element that hosts all blocks is not mounted. The container's bounding rect is required to compute absolute coordinates for Electron's capturePage, so the operation cannot proceed.","triggerScenarios":"The RPC runs while the tab's display container is unmounted — during tab close, window minimize with unmounted DOM, or before the layout component's ref has attached (very early after mount).","commonSituations":"Automated screenshot right after window/tab creation racing React's commit; capturing during workspace/tab teardown; tests or headless environments where the display container never renders.","solutions":["Wait until the tab is fully rendered before capturing (e.g. await a mounted flag or requestAnimationFrame)","Retry the RPC after a short delay if it races mount/unmount","Cancel queued screenshot requests when the tab/window closes","Verify the block is in the visible tab, not a background tab whose container is unmounted"],"exampleFix":"// before\nconst containerRect = displayContainer.getBoundingClientRect();\n// after\nif (!displayContainer) {\n    await new Promise((r) => requestAnimationFrame(r));\n    displayContainer = layoutModel.displayContainerRef.current;\n    if (!displayContainer) throw new Error(\"Display container not found\");\n}\nconst containerRect = displayContainer.getBoundingClientRect();","handlingStrategy":"retry","validationCode":"const displayContainer = getLayoutModelForStaticTab()?.displayContainerRef.current;\nif (!displayContainer) {\n    throw new Error(\"display container not mounted; cannot capture\");\n}","typeGuard":"function displayContainerMounted(): boolean {\n    return getLayoutModelForStaticTab()?.displayContainerRef.current != null;\n}","tryCatchPattern":"try {\n    const pngData = await rpcService.call(\"captureblockscreenshot\", { blockid });\n} catch (e) {\n    if (String(e).includes(\"Display container not found\")) {\n        await nextFrame();\n        pngData = await rpcService.call(\"captureblockscreenshot\", { blockid });\n    } else {\n        throw e;\n    }\n}","preventionTips":["Defer captures until after mount (requestAnimationFrame or mounted callback)","Skip captures for background tabs whose containers are unmounted","Guard ref consumers against null .current before layout commit"],"tags":["dom","lifecycle","screenshot"],"backgroundTag":"dom-element-not-mounted","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}