{"record":{"id":"cf48896b4cd712e4","repo":"garrytan/gstack","slug":"load-html-from-file-html-does-not-start-with-a","errorCode":null,"errorMessage":"load-html: --from-file html does not start with a valid markup opener","messagePattern":"load-html: --from-file html does not start with a valid markup opener","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/write-commands.ts","lineNumber":242,"sourceCode":"        } else if (args[i].startsWith('--')) {\n          throw new Error(`Unknown flag: ${args[i]}`);\n        } else if (!filePath) {\n          filePath = args[i];\n        }\n      }\n\n      // Inline HTML path: validate size + magic byte, then setContent directly.\n      if (fromFilePayload) {\n        const MAX_BYTES = parseInt(process.env.GSTACK_BROWSE_MAX_HTML_BYTES || '', 10) || (50 * 1024 * 1024);\n        if (Buffer.byteLength(fromFilePayload.html, 'utf8') > MAX_BYTES) {\n          throw new Error(\n            `load-html: --from-file html too large (> ${MAX_BYTES} bytes). ` +\n            'Raise with GSTACK_BROWSE_MAX_HTML_BYTES=<N>.'\n          );\n        }\n        const peek = fromFilePayload.html.trimStart();\n        if (!/^<[a-zA-Z!?]/.test(peek)) {\n          throw new Error('load-html: --from-file html does not start with a valid markup opener');\n        }\n        const finalWaitUntil = fromFilePayload.waitUntil ?? waitUntil;\n        await session.setTabContent(fromFilePayload.html, { waitUntil: finalWaitUntil });\n        return `Loaded HTML: (inline from --from-file, ${fromFilePayload.html.length} chars)`;\n      }\n\n      if (!filePath) throw new Error('Usage: browse load-html <file> [--wait-until load|domcontentloaded|networkidle] [--tab-id <N>]  |  load-html --from-file <payload.json> [--tab-id <N>]');\n\n      // Extension allowlist\n      const ALLOWED_EXT = ['.html', '.htm', '.xhtml', '.svg'];\n      const ext = path.extname(filePath).toLowerCase();\n      if (!ALLOWED_EXT.includes(ext)) {\n        throw new Error(\n          `load-html: file does not appear to be HTML. Expected .html/.htm/.xhtml/.svg, got ${ext || '(no extension)'}. Rename the file if it's really HTML.`\n        );\n      }\n\n      const absolutePath = path.resolve(filePath);","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L224-L260","documentation":"Content-sniff guard at write-commands.ts:241-243. After trimming leading whitespace, the html string must match /^<[a-zA-Z!?]/ — i.e. it begins with a tag character, '!' (doctype/comment), or '?' (XML prolog). This rejects non-markup content so the --from-file path doesn't silently render JSON, plaintext, or data as a blank page.","triggerScenarios":"html starting with plain text, a JSON object, a markdown heading, whitespace-only content, a BOM that survives trim, or '<' followed by a digit/space (e.g. '<123').","commonSituations":"Accidentally placing the JSON wrapper as the html value; HTML prefixed with a comment then leading text; markdown or templating output passed as HTML; a BOM-only or empty payload.","solutions":["Ensure html begins with a tag, <!doctype html>, <!-- comment -->, or <?xml prolog","Strip any leading BOM and non-markup preamble","Verify the html field holds markup, not the JSON envelope or a path"],"exampleFix":"// before — {\"html\": \"Hello world\"}  (plain text, no opener)\n// after — {\"html\": \"<!doctype html><html>...Hello world...</html>\"}","handlingStrategy":"validation","validationCode":"function startsLikeMarkup(html: string): boolean {\n  return /^<[a-zA-Z!?]/.test(html.trimStart())\n}","typeGuard":"function isMarkupOpenable(html: string): boolean {\n  return /^<[a-zA-Z!?]/.test(html.trimStart())\n}","tryCatchPattern":null,"preventionTips":["Ensure html begins with a tag, <!doctype, <!--, or <?xml","Strip leading BOM and non-markup preamble","Confirm the field holds markup, not the JSON envelope or a path"],"tags":["load-html","validation","content-sniff","write-commands"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}