wavetermdev/waveterm · error

Layout model not found

Error message

Layout model not found

What it means

captureBlockScreenshot needs the current static tab's LayoutModel to locate a block's DOM node and compute its on-screen rectangle for Electron's capturePage. getLayoutModelForStaticTab() returned null, meaning no layout model is registered for the active static tab. This is a lifecycle/state error: the screenshot RPC was invoked when the tab's layout system was not initialized or has been torn down.

Source

Thrown at frontend/app/store/tabrpcclient.ts:25

import { WorkspaceLayoutModel } from "@/app/workspace/workspace-layout-model";
import { getLayoutModelForStaticTab } from "@/layout/index";
import { base64ToArrayBuffer } from "@/util/util";
import { RpcResponseHelper, WshClient } from "./wshclient";
import { RpcApi } from "./wshclientapi";

export class TabClient extends WshClient {
    constructor(routeId: string) {
        super(routeId);
    }

    handle_captureblockscreenshot(rh: RpcResponseHelper, data: CommandCaptureBlockScreenshotData): Promise<string> {
        return this.captureBlockScreenshot(data.blockid);
    }

    async captureBlockScreenshot(blockId: string): Promise<string> {
        const layoutModel = getLayoutModelForStaticTab();
        if (!layoutModel) {
            throw new Error("Layout model not found");
        }

        const node = layoutModel.getNodeByBlockId(blockId);
        if (!node) {
            throw new Error(`Block not found: ${blockId}`);
        }

        const displayContainer = layoutModel.displayContainerRef.current;
        if (!displayContainer) {
            throw new Error("Display container not found");
        }

        const containerRect = displayContainer.getBoundingClientRect();
        const additionalProps = layoutModel.getNodeAdditionalProperties(node);

        let electronRect: Electron.Rectangle;

        if (!additionalProps?.rect) {

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check that the block's tab is open and its layout has fully mounted before calling the RPC
  2. Retry after a short delay (e.g. wait for the tab to render) if called during tab transitions
  3. Confirm the call is routed to the correct tab's TabRpcClient, not a stale/closed one
  4. If screenshotting many blocks, fetch the layout model once after confirming it exists rather than during transitions

Example fix

// before
const layoutModel = getLayoutModelForStaticTab();
if (!layoutModel) {
    throw new Error("Layout model not found");
}
// after
const layoutModel = getLayoutModelForStaticTab();
if (!layoutModel) {
    await waitForLayoutModel(500);
    layoutModel = getLayoutModelForStaticTab();
}
if (!layoutModel) {
    throw new Error("Layout model not found");
}
Defensive patterns

Strategy: retry

Validate before calling

const layoutModel = getLayoutModelForStaticTab();
if (layoutModel == null) {
    throw new Error("cannot capture screenshot: tab layout not mounted yet");
}

Type guard

function hasLayoutModel(): boolean {
    return getLayoutModelForStaticTab() != null;
}

Try / catch

try {
    const pngData = await rpcService.call("captureblockscreenshot", { blockid });
} catch (e) {
    if (String(e).includes("Layout model not found")) {
        await delay(150);
        pngData = await rpcService.call("captureblockscreenshot", { blockid });
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: handle_captureblockscreenshot RPC arrives before the tab's React layout has mounted, after the tab/window was closed, or in a context (e.g. a preview/test static tab) where getLayoutModelForStaticTab() has no registered model.

Common situations: Client calls captureblockscreenshot right after tab switch/creation before mount completes; screenshotting a block in a closed window; running in an environment (storybook/tests/web) where the static-tab layout model is never set.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/d9c15791c2b60884. Report an issue: GitHub.