{"record":{"id":"26d660597d05299b","repo":"windmill-labs/windmill","slug":"the-app-preview-is-collapsed-so-there-is-nothing","errorCode":null,"errorMessage":"The app preview is collapsed, so there is nothing to capture. Ask the user to expand the preview panel, then try again.","messagePattern":"The app preview is collapsed, so there is nothing to capture\\. Ask the user to expand the preview panel, then try again\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/raw_apps/RawAppEditor.svelte","lineNumber":1879,"sourceCode":"\t\treturn () => restores.forEach((r) => r())\n\t}\n\n\t// Capture the live preview as a PNG data URL. The preview iframe\n\t// (/ui_builder/app-preview.html) is same-origin with no sandbox, so its rendered\n\t// document is reachable and can be serialized from here. There is no native\n\t// element-screenshot API; modern-screenshot reconstructs the DOM into an SVG\n\t// foreignObject, so a WebGL canvas is only captured when its context was created\n\t// with preserveDrawingBuffer. Lazy-imported so the library only loads on demand.\n\tconst captureScreenshot: RawAppScreenshotRequester = async () => {\n\t\tconst target = previewIframe?.contentDocument?.body\n\t\tif (!previewIframe || !previewIframeLoaded || !target) {\n\t\t\tthrow new Error('App preview is not ready')\n\t\t}\n\t\t// Collapsing the preview leaves the iframe mounted and populated at zero\n\t\t// width, which passes every check above and then fails inside the rasteriser\n\t\t// as an opaque decode error. Name the cause so the agent can act on it.\n\t\tif (!target.clientWidth || !target.clientHeight) {\n\t\t\tthrow new Error(\n\t\t\t\t'The app preview is collapsed, so there is nothing to capture. Ask the user to expand the preview panel, then try again.'\n\t\t\t)\n\t\t}\n\t\tconst { domToPng } = await import('modern-screenshot')\n\t\t// Above CSS resolution for small previews (a 1× capture of a ~900px preview\n\t\t// reads blurry next to the live render), sub-1× for oversized bodies — see\n\t\t// captureScale. maximumCanvasSize is the belt over that math: the rasterised\n\t\t// box can exceed the body's client size, and an unbounded canvas on a tall\n\t\t// scrolling app can freeze the tab before normalize ever bounds the pixels.\n\t\tconst scale = captureScale(Math.max(target.clientWidth, target.clientHeight))\n\t\tconst restore = pinSingleLineText(target)\n\t\ttry {\n\t\t\treturn await domToPng(target, {\n\t\t\t\tbackgroundColor: '#ffffff',\n\t\t\t\tscale,\n\t\t\t\tmaximumCanvasSize: MAX_IMAGE_EDGE\n\t\t\t})\n\t\t} finally {","sourceCodeStart":1861,"sourceCodeEnd":1897,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/raw_apps/RawAppEditor.svelte#L1861-L1897","documentation":"The raw-app screenshot/capture helper rasterises the app preview iframe via modern-screenshot. When the preview panel is collapsed, the iframe stays mounted and populated but has zero width/height, which passes the earlier readiness checks and would fail inside the rasteriser as an opaque decode error. The code checks clientWidth/clientHeight up front and throws this named error so the agent knows to ask the user to expand the preview before retrying.","triggerScenarios":"Calling the capture/screenshot action while the app preview panel in RawAppEditor is collapsed (target.clientWidth or target.clientHeight is 0), even though the iframe is loaded and passes URL/readiness checks.","commonSituations":"A user or agent asks the AI assistant to snapshot/export the app while the preview pane is collapsed; narrow side-by-side layouts auto-collapse the preview; the user resized the preview to zero width before triggering capture.","solutions":["Expand the app preview panel in the RawAppEditor so it has non-zero width and height, then retry the capture","If the layout is too narrow, widen the editor window or drag the splitter to give the preview visible space","Retry the capture request after the preview is visibly rendered"],"exampleFix":"// agent-side retry loop\nif (err.message.includes('preview is collapsed')) {\n  await expandPreviewPanel();\n  await capturePreview();\n}","handlingStrategy":"validation","validationCode":"const el = document.querySelector('.app-preview iframe');\nif (!el || el.clientWidth === 0 || el.clientHeight === 0) {\n  throw new Error('Preview collapsed; expand before capture');\n}","typeGuard":"function isPreviewVisible(el: HTMLElement): boolean {\n  return el.clientWidth > 0 && el.clientHeight > 0;\n}","tryCatchPattern":"try { await capturePreview(); } catch (e) {\n  if (e.message.includes('preview is collapsed')) { promptExpandPreview(); }\n  else throw e;\n}","preventionTips":["Check clientWidth/clientHeight before any rasterisation call","Keep the preview panel expanded (or auto-expand) when capture is requested","Surface the collapse state in the UI so capture is disabled while collapsed"],"tags":["ui","screenshot","preview","agent"],"backgroundTag":"preview-panel-collapsed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}