jackwener/OpenCLI · warning · AuthRequiredError

guazi ${contextHint} hit an anti-bot challenge — Guazi may h

Error message

guazi ${contextHint} hit an anti-bot challenge — Guazi may have started gating the mobile site.

What it means

After fetching the page, guaziFetch scans the HTML for anti-bot markers (瑞数, reese84, captcha, 滑动验证, verify.guazi, 安全验证) and throws AuthRequiredError when one appears and the page is not a real car-detail page. This signals Guazi has started gating the mobile site behind a JavaScript/CAPTCHA challenge, meaning plain HTTP scraping can no longer proceed.

Source

Thrown at clis/guazi/utils.js:125

    let resp;
    try {
        resp = await fetch(`${GUAZI_M_BASE}${path}`, {
            headers: {
                'User-Agent': UA,
                Referer: `${GUAZI_M_BASE}/`,
                'Accept-Language': 'zh-CN,zh;q=0.9',
            },
        });
    } catch (err) {
        throw new CommandExecutionError(`guazi ${contextHint} network error: ${err?.message || err}`);
    }
    if (!resp.ok) {
        throw new CommandExecutionError(`guazi ${contextHint} HTTP ${resp.status}`);
    }
    const html = await resp.text();
    // Guazi may eventually push the mobile pages behind their JS challenge.
    if (/瑞数|reese84|captcha|滑动验证|verify\.guazi|安全验证/i.test(html) && !/car-detail\/c\d+/.test(html)) {
        throw new AuthRequiredError(
            'guazi.com',
            `guazi ${contextHint} hit an anti-bot challenge — Guazi may have started gating the mobile site.`,
        );
    }
    return html;
}

export { ArgumentError, CommandExecutionError, EmptyResultError };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Switch to a residential IP or lower request rate and retry
  2. Open the same URL in a real browser to confirm whether gating is site-wide or IP-specific
  3. If gating is permanent, migrate to Guazi's official API or a headless-browser approach that can solve the JS challenge
  4. Handle AuthRequiredError in the CLI to surface an actionable message to the user

Example fix

// before
const html = await guaziFetch('/car/123', 'car page');
// AuthRequiredError: guazi car page hit an anti-bot challenge...

// after
try {
  const html = await guaziFetch('/car/123', 'car page');
} catch (e) {
  if (e instanceof AuthRequiredError) {
    // fall back to cached data or inform user the site is gated
  }
}
Defensive patterns

Strategy: fallback

Validate before calling

const probe = await fetch(`${GUAZI_M_BASE}/`, { headers: { 'User-Agent': UA } });
const body = await probe.text();
const gated = /瑞数|reese84|captcha|滑动验证|verify\.guazi|安全验证/i.test(body);
if (gated) throw new Error('guazi is gated for this IP — use a proxy or headless browser');

Type guard

const isAuthRequired = (e) => e instanceof AuthRequiredError;

Try / catch

try {
  const html = await guaziFetch(path, hint);
} catch (e) {
  if (isAuthRequired(e)) {
    // fall back to cached data or a headless-browser path
    return headlessFetch(path);
  }
  throw e;
}

Prevention

When it happens

Trigger: guaziFetch returning HTML whose body matches the anti-bot regex while lacking a car-detail/c\d+ marker — i.e. Guazi served a challenge/captcha interstitial instead of content.

Common situations: IP reputation-based gating (datacenter/VPN IPs); Guazi deploying a JS challenge (e.g. RiverSecurity/瑞数) sitewide; burst traffic from the scraper tripping the WAF.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/2bf5b5095e2cbc1d. Report an issue: GitHub.