{"record":{"id":"310146288794d59e","repo":"garrytan/gstack","slug":"cannot-use-load-html-inside-a-frame-run-frame-ma","errorCode":null,"errorMessage":"Cannot use load-html inside a frame. Run 'frame main' first.","messagePattern":"Cannot use load-html inside a frame\\. Run 'frame main' first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/write-commands.ts","lineNumber":179,"sourceCode":"      return `Back → ${page.url()}`;\n    }\n\n    case 'forward': {\n      if (inFrame) throw new Error('Cannot use forward inside a frame. Run \\'frame main\\' first.');\n      session.clearLoadedHtml();\n      await page.goForward({ waitUntil: 'domcontentloaded', timeout: 15000 });\n      return `Forward → ${page.url()}`;\n    }\n\n    case 'reload': {\n      if (inFrame) throw new Error('Cannot use reload inside a frame. Run \\'frame main\\' first.');\n      session.clearLoadedHtml();\n      await page.reload({ waitUntil: 'domcontentloaded', timeout: 15000 });\n      return `Reloaded ${page.url()}`;\n    }\n\n    case 'load-html': {\n      if (inFrame) throw new Error('Cannot use load-html inside a frame. Run \\'frame main\\' first.');\n\n      // --from-file <path.json>: read inline HTML from a JSON payload. Used by\n      // make-pdf to dodge Windows argv size limits on large rendered HTML.\n      // The JSON shape is { html: string, waitUntil?: \"load\"|\"domcontentloaded\"|\"networkidle\" }.\n      // The safe-dirs + magic-byte + size-cap checks below still apply to the\n      // INLINE HTML content, not to the payload file path itself.\n      let fromFilePayload: { html: string; waitUntil?: SetContentWaitUntil } | null = null;\n      let filePath: string | undefined;\n      let waitUntil: SetContentWaitUntil = 'domcontentloaded';\n      for (let i = 0; i < args.length; i++) {\n        if (args[i] === '--from-file') {\n          const payloadPath = args[++i];\n          if (!payloadPath) throw new Error('load-html: --from-file requires a path');\n          // Parity with the sibling `load-html <file>` path below (line 249):\n          // that branch runs every `file://` target through validateReadPath\n          // so the safe-dirs policy can't be side-stepped. Same policy must\n          // apply here — otherwise --from-file becomes a read-anywhere escape\n          // hatch for any caller that can pick the payload path (e.g., an","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L161-L197","documentation":"Frame-context guard in the load-html case at write-commands.ts:181. setContent operates on the top-level page; with a subframe selected it is refused for the same reason as goto/back/forward/reload — page-level operations cannot run against a frame-scoped session.","triggerScenarios":"Running 'load-html' (either the file path or --from-file form) while a frame context is active.","commonSituations":"Loading fixture HTML after a prior step entered an iframe and never reset to main.","solutions":["Run 'frame main' before 'load-html'","Load HTML fixtures at the start of the flow, before any frame entry","Guard on session.getFrame() === null"],"exampleFix":"// before\nawait handleWriteCommand('load-html', ['--from-file','p.json'], session, bm)  // in frame → throws\n// after\nawait handleWriteCommand('frame', ['main'], session, bm)\nawait handleWriteCommand('load-html', ['--from-file','p.json'], session, bm)","handlingStrategy":"validation","validationCode":"function canNavigate(session: { getFrame(): unknown }): boolean {\n  return session.getFrame() === null\n}","typeGuard":"function isMainFrameSession(s: { getFrame(): unknown }): boolean {\n  return s.getFrame() === null\n}","tryCatchPattern":null,"preventionTips":["Run 'frame main' before 'load-html'","Load fixtures before entering any frame","Assert getFrame() === null"],"tags":["frames","load-html","write-commands","session-state"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}