garrytan/gstack · error · Error

Invalid heatmap color "${color}" for ${ref}. Valid: ${[...VA

Error message

Invalid heatmap color "${color}" for ${ref}. Valid: ${[...VALID_COLORS].join(', ')}

What it means

Thrown after a successful JSON parse when at least one value in the heatmap object is not in the allowed color set {green, yellow, red, blue, orange, gray}. The error names the offending color, the ref it was attached to, and the valid list so the caller can fix that one entry.

Source

Thrown at browse/src/snapshot.ts:501

      orange: { border: '#ff6600', bg: 'rgba(255,102,0,0.15)' },
      gray:   { border: '#888888', bg: 'rgba(136,136,136,0.15)' },
    };

    let colorAssignments: Record<string, string>;
    try {
      const parsed = JSON.parse(opts.heatmap);
      if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
        throw new Error('not an object');
      }
      colorAssignments = parsed;
    } catch {
      throw new Error('Invalid heatmap JSON. Expected object: \'{"@e1":"green","@e3":"red"}\'');
    }

    // Validate colors
    for (const [ref, color] of Object.entries(colorAssignments)) {
      if (!VALID_COLORS.has(color)) {
        throw new Error(`Invalid heatmap color "${color}" for ${ref}. Valid: ${[...VALID_COLORS].join(', ')}`);
      }
    }

    try {
      const boxes: Array<{ ref: string; box: { x: number; y: number; width: number; height: number }; color: string }> = [];
      for (const [refKey, color] of Object.entries(colorAssignments)) {
        const cleanRef = refKey.startsWith('@') ? refKey.slice(1) : refKey;
        const entry = refMap.get(cleanRef);
        if (!entry) continue; // Skip refs not found on page
        try {
          const box = await entry.locator.boundingBox({ timeout: 1000 });
          if (box) {
            const colors = COLOR_MAP[color] || COLOR_MAP.gray;
            boxes.push({ ref: `@${cleanRef}`, box, color: JSON.stringify(colors) });
          }
        } catch {
          // Element may be offscreen or hidden — skip
        }

View on GitHub (pinned to 94993f7401)

Solutions

  1. Replace the offending value with one of: green, yellow, red, blue, orange, gray.
  2. If you need a custom color, fork the COLOR_MAP and VALID_COLORS set in snapshot.ts — but note this changes the public contract.
  3. Lower-case the values before serializing to avoid case mismatches.
  4. Strip leading `#` and hex codes — the API takes color NAMES, not codes.

Example fix

// before
snapshot(page, { heatmap: '{"@e1":"#ff0000","@e3":"purple"}' });
// after
snapshot(page, { heatmap: '{"@e1":"red","@e3":"gray"}' });
Defensive patterns

Strategy: validation

Validate before calling

const VALID_COLORS = new Set(['green','yellow','red','blue','orange','gray']);
function validateHeatmapColors(obj: Record<string, string>): void {
  for (const [ref, color] of Object.entries(obj)) {
    if (!VALID_COLORS.has(color)) {
      throw new Error(`Invalid heatmap color "${color}" for ${ref}. Valid: ${[...VALID_COLORS].join(', ')}`);
    }
  }
}

Type guard

const isHeatmapColor = (c: string): boolean =>
  ['green','yellow','red','blue','orange','gray'].includes(c);

Try / catch

try {
  await snapshot(session, { heatmap: json });
} catch (e: any) {
  if (/^Invalid heatmap color/.test(e.message)) {
    // normalize: clamp unknown colors to gray and retry
    const fixed = remapColors(json, c => isHeatmapColor(c) ? c : 'gray');
    await snapshot(session, { heatmap: JSON.stringify(fixed) });
  } else throw e;
}

Prevention

When it happens

Trigger: Passing a heatmap object whose value is a hex code (`'#ff0000'`), a CSS color keyword outside the allow-list (`purple`), a typo (`gren`), or any non-string type.

Common situations: Reusing a CSS palette that includes colors not in the allow-list; case mismatch (`Red` vs `red` — the check is case-sensitive); a teammate adding a custom color without realizing the set is closed.

Related errors


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