garrytan/gstack · error · Error

Invalid state file: expected cookies and pages arrays

Error message

Invalid state file: expected cookies and pages arrays

What it means

After reading `<name>.json`, the loader validates that both `data.cookies` and `data.pages` are arrays (line 957). If either is missing or not an array the file is rejected as structurally invalid — partial restoration would silently drop cookies or tabs. Subsequent cookie entries are validated separately (lines 959-967).

Source

Thrown at browse/src/meta-commands.ts:957

      if (action === 'save') {
        const state = await bm.saveState();
        // V1: cookies + URLs only (not localStorage — breaks on load-before-navigate)
        const saveData = {
          version: 1,
          savedAt: new Date().toISOString(),
          cookies: state.cookies,
          pages: state.pages.map(p => ({ url: p.url, isActive: p.isActive })),
        };
        writeSecureFile(statePath, JSON.stringify(saveData, null, 2));
        return `State saved: ${statePath} (${state.cookies.length} cookies, ${state.pages.length} pages)\n⚠️  Cookies stored in plaintext. Delete when no longer needed.`;
      }

      if (action === 'load') {
        if (!fs.existsSync(statePath)) throw new Error(`State not found: ${statePath}`);
        const data = JSON.parse(fs.readFileSync(statePath, 'utf-8'));
        if (!Array.isArray(data.cookies) || !Array.isArray(data.pages)) {
          throw new Error('Invalid state file: expected cookies and pages arrays');
        }
        // Validate and filter cookies — reject malformed or internal-network cookies
        const validatedCookies = data.cookies.filter((c: any) => {
          if (typeof c !== 'object' || !c) return false;
          if (typeof c.name !== 'string' || typeof c.value !== 'string') return false;
          if (typeof c.domain !== 'string' || !c.domain) return false;
          const d = c.domain.startsWith('.') ? c.domain.slice(1) : c.domain;
          if (d === 'localhost' || d.endsWith('.internal') || d === '169.254.169.254') return false;
          return true;
        });
        if (validatedCookies.length < data.cookies.length) {
          console.warn(`[browse] Filtered ${data.cookies.length - validatedCookies.length} invalid cookies from state file`);
        }
        // Warn on state files older than 7 days
        if (data.savedAt) {
          const ageMs = Date.now() - new Date(data.savedAt).getTime();
          const SEVEN_DAYS = 7 * 24 * 60 * 60 * 1000;
          if (ageMs > SEVEN_DAYS) {

View on GitHub (pinned to 94993f7401)

Solutions

  1. Re-save a fresh state with `browse state save <name>` and load that.
  2. If migrating from another format, transform the JSON to `{ cookies: [...], pages: [...] }` before loading.
  3. Discard the corrupt file and recreate the session manually.

Example fix

// before (file content)
{ "session": { "cookies": [], "pages": [] } }
// after
{ "version": 1, "savedAt": "...", "cookies": [], "pages": [] }
Defensive patterns

Strategy: type-guard

Validate before calling

const data = JSON.parse(raw);
if (!Array.isArray(data?.cookies) || !Array.isArray(data?.pages)) {
  throw new Error('State file schema mismatch: expected { cookies: [], pages: [] }');
}

Type guard

const isStateFile = (d: unknown): d is { cookies: unknown[]; pages: unknown[] } =>
  typeof d === 'object' && d !== null &&
  Array.isArray((d as any).cookies) && Array.isArray((d as any).pages);

Try / catch

try { await browse.state('load', name); }
catch (err) {
  if (/Invalid state file/.test(err.message)) {
    // re-save a fresh state and discard the corrupt file
  }
}

Prevention

When it happens

Trigger: Loading a hand-edited JSON, a file from a different tool/version, a truncated write, or a future schema where `cookies`/`pages` was renamed.

Common situations: Manual edits to a saved state file, cross-version migration (the `version: 1` schema changed), or disk corruption / partial writes.

Related errors


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