{"record":{"id":"a53505edd54cb649","repo":"garrytan/gstack","slug":"cannot-use-forward-inside-a-frame-run-frame-main","errorCode":null,"errorMessage":"Cannot use forward inside a frame. Run 'frame main' first.","messagePattern":"Cannot use forward inside a frame\\. Run 'frame main' first\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/write-commands.ts","lineNumber":165,"sourceCode":"      if (!url) throw new Error('Usage: browse goto <url>');\n      // Clear loadedHtml BEFORE navigation — a timeout after the main-frame commit\n      // must not leave stale content that could resurrect on a later context recreation.\n      session.clearLoadedHtml();\n      const normalizedUrl = await validateNavigationUrl(url);\n      const response = await page.goto(normalizedUrl, { waitUntil: 'domcontentloaded', timeout: 15000 });\n      const status = response?.status() || 'unknown';\n      return `Navigated to ${normalizedUrl} (${status})`;\n    }\n\n    case 'back': {\n      if (inFrame) throw new Error('Cannot use back inside a frame. Run \\'frame main\\' first.');\n      session.clearLoadedHtml();\n      await page.goBack({ waitUntil: 'domcontentloaded', timeout: 15000 });\n      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\" }.","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L147-L183","documentation":"Frame-context guard in the forward case at write-commands.ts:166. page.goForward() is a top-level-page operation and is blocked when a subframe context is active (session.getFrame() !== null).","triggerScenarios":"Running 'forward' while a frame context is active.","commonSituations":"Continuing an automated session after entering a frame, without returning to the main frame.","solutions":["Run 'frame main' before 'forward'","Keep all top-level navigation outside of frame-scoped blocks","Check session.getFrame() === null before calling"],"exampleFix":"// before\nawait handleWriteCommand('forward', [], session, bm)  // in frame → throws\n// after\nawait handleWriteCommand('frame', ['main'], session, bm)\nawait handleWriteCommand('forward', [], 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 'forward'","Sequence navigations before frame entry","Guard on getFrame() === null"],"tags":["frames","navigation","write-commands","session-state"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}