garrytan/gstack · error · Error

Invalid --wait-until '${val}'. Must be one of: load, domcont

Error message

Invalid --wait-until '${val}'. Must be one of: load, domcontentloaded, networkidle.

What it means

CLI-flag validation at write-commands.ts:219-222. The --wait-until flag (distinct from the JSON payload's waitUntil) got a value that is not load, domcontentloaded, or networkidle. This is the command-line form of the same constraint.

Source

Thrown at browse/src/write-commands.ts:221

              `load-html: --from-file ${payloadPath} must be under ${SAFE_DIRECTORIES.join(' or ')} (security policy). Copy the payload into the project tree or /tmp first.`
            );
          }
          const raw = fs.readFileSync(payloadPath, 'utf8');
          let json: any;
          try { json = JSON.parse(raw); }
          catch (e: any) { throw new Error(`load-html: --from-file JSON parse failed: ${e.message}`); }
          if (typeof json.html !== 'string') {
            throw new Error('load-html: --from-file JSON must have a "html" string field');
          }
          if (json.waitUntil && json.waitUntil !== 'load'
              && json.waitUntil !== 'domcontentloaded' && json.waitUntil !== 'networkidle') {
            throw new Error(`load-html: --from-file waitUntil '${json.waitUntil}' invalid`);
          }
          fromFilePayload = { html: json.html, waitUntil: json.waitUntil };
        } else if (args[i] === '--wait-until') {
          const val = args[++i];
          if (val !== 'load' && val !== 'domcontentloaded' && val !== 'networkidle') {
            throw new Error(`Invalid --wait-until '${val}'. Must be one of: load, domcontentloaded, networkidle.`);
          }
          waitUntil = val;
        } else if (args[i].startsWith('--')) {
          throw new Error(`Unknown flag: ${args[i]}`);
        } else if (!filePath) {
          filePath = args[i];
        }
      }

      // Inline HTML path: validate size + magic byte, then setContent directly.
      if (fromFilePayload) {
        const MAX_BYTES = parseInt(process.env.GSTACK_BROWSE_MAX_HTML_BYTES || '', 10) || (50 * 1024 * 1024);
        if (Buffer.byteLength(fromFilePayload.html, 'utf8') > MAX_BYTES) {
          throw new Error(
            `load-html: --from-file html too large (> ${MAX_BYTES} bytes). ` +
            'Raise with GSTACK_BROWSE_MAX_HTML_BYTES=<N>.'
          );
        }

View on GitHub (pinned to 94993f7401)

Solutions

  1. Use one of: load, domcontentloaded, networkidle
  2. Drop the flag to use the default (domcontentloaded)

Example fix

// before
load-html page.html --wait-until none
// after
load-html page.html --wait-until networkidle
Defensive patterns

Strategy: validation

Validate before calling

const WAIT_UNTIL = new Set(['load','domcontentloaded','networkidle'])
function validCliWaitUntil(v: string): boolean {
  return WAIT_UNTIL.has(v)
}

Type guard

function isCliWaitUntil(v: string): v is 'load'|'domcontentloaded'|'networkidle' {
  return ['load','domcontentloaded','networkidle'].includes(v)
}

Prevention

When it happens

Trigger: Invoking load-html --wait-until <bad> <file>, e.g. --wait-until none, --wait-until idle, --wait-until ready.

Common situations: Typing a value from a different framework's API; autocomplete inserting the wrong token; copy-paste from Playwright page.goto docs that list extra strategies.

Related errors


AI-assisted analysis of garrytan/gstack@94993f7401 (2026-08-12). Data as JSON: /api/errors/5e7f765da25af687. Report an issue: GitHub.