{"record":{"id":"84d437c87f1e3600","repo":"garrytan/gstack","slug":"load-html-from-file-requires-a-path","errorCode":null,"errorMessage":"load-html: --from-file requires a path","messagePattern":"load-html: --from-file requires a path","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"browse/src/write-commands.ts","lineNumber":192,"sourceCode":"      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\n          // MCP caller issuing load-html with an attacker-influenced path).\n          try {\n            validateReadPath(path.resolve(payloadPath));\n          } catch {\n            throw new Error(\n              `load-html: --from-file ${payloadPath} must be under ${SAFE_DIRECTORIES.join(' or ')} (security policy). Copy the payload into the project tree or /tmp first.`\n            );\n          }\n          const raw = fs.readFileSync(payloadPath, 'utf8');\n          let json: any;\n          try { json = JSON.parse(raw); }\n          catch (e: any) { throw new Error(`load-html: --from-file JSON parse failed: ${e.message}`); }\n          if (typeof json.html !== 'string') {","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L174-L210","documentation":"Argument guard at write-commands.ts:192. The --from-file flag consumes the next token via args[++i]; if that token is undefined (--from-file is the last arg) or empty, payloadPath is falsy and the command refuses to proceed rather than reading an unintended path.","triggerScenarios":"load-html --from-file with no following token (last argument), or followed by an empty string; e.g. 'load-html --from-file' alone.","commonSituations":"Truncated command, a templating bug that drops the path, or quoting that yields an empty value.","solutions":["Supply the payload path immediately after the flag: load-html --from-file ./payload.json","Validate the args array length in automation before invoking","Ensure the path token is non-empty and present"],"exampleFix":"// before\nawait handleWriteCommand('load-html', ['--from-file'], session, bm)\n// after\nawait handleWriteCommand('load-html', ['--from-file', './payload.json'], session, bm)","handlingStrategy":"validation","validationCode":"function requireFromFilePath(args: string[], i: number): string {\n  const p = args[i + 1]\n  if (!p) throw new Error('--from-file requires a path')\n  return p\n}","typeGuard":"function hasFromFileTarget(args: string[]): boolean {\n  const i = args.indexOf('--from-file')\n  return i >= 0 && typeof args[i + 1] === 'string' && args[i + 1].length > 0\n}","tryCatchPattern":null,"preventionTips":["Always pair --from-file with an immediate path token","Validate args length in automation before invoking"],"tags":["usage","arguments","load-html","write-commands"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}