{"record":{"id":"078eaea0909cd80a","repo":"garrytan/gstack","slug":"diagram-render-bundle-did-not-become-ready-in-the","errorCode":null,"errorMessage":"diagram-render bundle did not become ready in the browse tab (${READY_TIMEOUT_MS}ms). Check `browse js \"window.__errors\"` on tab ${this.tabId}.","messagePattern":"diagram-render bundle did not become ready in the browse tab \\((.+?)ms\\)\\. Check `browse js \"window\\.__errors\"` on tab (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"make-pdf/src/diagram-prepass.ts","lineNumber":367,"sourceCode":"        if (!survivorOk) throw renameErr;\n      }\n    }\n    const tabId = browseClient.newtab();\n    const tab = new RenderTab(tabId, staged);\n    tab.loadBundle();\n    return tab;\n  }\n\n  /** (Re)load the bundle page — also the reset path after a render error. */\n  loadBundle(): void {\n    browseClient.loadHtmlFile({ file: this.stagedBundlePath, tabId: this.tabId });\n    const ready = browseClient.waitForExpression({\n      expression: \"document.getElementById('status') !== null && document.getElementById('status').textContent === 'ready'\",\n      tabId: this.tabId,\n      timeoutMs: READY_TIMEOUT_MS,\n    });\n    if (!ready) {\n      throw new Error(\n        \"diagram-render bundle did not become ready in the browse tab \" +\n        `(${READY_TIMEOUT_MS}ms). Check \\`browse js \"window.__errors\"\\` on tab ${this.tabId}.`,\n      );\n    }\n  }\n\n  /**\n   * Call one of the bundle's async window functions with JSON-safe string\n   * args. Errors come back as a recognizable ERR: prefix so a render failure\n   * is data, not a thrown browse exit.\n   */\n  call(fn: string, ...args: Array<string | number>): string {\n    const argList = args.map((a) => JSON.stringify(a)).join(\",\");\n    const expression =\n      `window.${fn}(${argList})` +\n      `.then(r => \"OK:\" + r)` +\n      `.catch(e => \"ERR:\" + String((e && e.message) || e))`;\n    const result = this.js(expression);","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/make-pdf/src/diagram-prepass.ts#L349-L385","documentation":"Thrown by RenderTab.loadBundle() when the diagram-render bundle page does not expose a #status element reading 'ready' within READY_TIMEOUT_MS after loadHtmlFile. The bundle is the headless renderer for mermaid/excalidraw; if it never initializes, no fence can render. The message points at `window.__errors` on the tab for diagnostics.","triggerScenarios":"loadBundle() is called (initial load or the reset-after-error path) and waitForExpression times out. Causes: a bundle HTML file that is wrong/corrupt, a JS exception during bundle boot (visible in window.__errors), a wedged renderer, READY_TIMEOUT_MS too low for a cold Chromium, or a loadHtmlFile that silently failed.","commonSituations":"A stale diagram-render.html from an older build missing the status element; a CDN/runtime dependency the bundle expects is blocked (offline posture); Chromium sandbox failure on a fresh VM; the bundle was overwritten by a partial build; CJK or huge content exhausting memory at boot.","solutions":["Inspect bundle errors: `browse js \"window.__errors\"` on the tab id from the message.","Rebuild the bundle: `bun run build:diagram-render` (repo) or re-run ./setup (install).","Increase READY_TIMEOUT_MS if the daemon is cold and the machine is slow.","Confirm the bundle HTML resolves to the right file (see resolveBundlePath error 329)."],"exampleFix":"// before\nloadBundle(): void {\n  browseClient.loadHtmlFile({ file: this.stagedBundlePath, tabId: this.tabId });\n  const ready = browseClient.waitForExpression({ expression: \"...status==='ready'\", tabId: this.tabId, timeoutMs: READY_TIMEOUT_MS });\n  if (!ready) throw new Error(`diagram-render bundle did not become ready ...`);\n}\n\n// after: capture boot errors into the thrown message\nloadBundle(): void {\n  browseClient.loadHtmlFile({ file: this.stagedBundlePath, tabId: this.tabId });\n  const ready = browseClient.waitForExpression({ expression: \"...status==='ready'\", tabId: this.tabId, timeoutMs: READY_TIMEOUT_MS });\n  if (!ready) {\n    const errs = browseClient.js({ expression: 'JSON.stringify(window.__errors ?? [])', tabId: this.tabId });\n    throw new Error(`diagram-render bundle did not become ready (${READY_TIMEOUT_MS}ms). Boot errors: ${errs}`);\n  }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"async function loadBundleWithRetry(tab: RenderTab, attempts = 2): Promise<void> {\n  for (let i = 0; i < attempts; i++) {\n    try {\n      tab.loadBundle();\n      return;\n    } catch (e) {\n      if (i === attempts - 1) throw e;\n      // reload the tab from scratch before retrying\n      await new Promise(r => setTimeout(r, 500));\n    }\n  }\n}","preventionTips":["Rebuild the bundle (`bun run build:diagram-render`) after pulling the repo.","Inspect window.__errors immediately when a loadBundle fails.","Give the daemon a warm-up render before timing-sensitive runs.","Keep READY_TIMEOUT_MS comfortably above the worst observed cold-start."],"tags":["make-pdf","diagram","render","browse","timeout"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}