jackwener/OpenCLI · error · CommandExecutionError

HTTP ${code}

Error message

HTTP ${code}

What it means

fetchKeJson performs an in-browser fetch against ke.com APIs with credentials included. When the response is not ok (status other than 2xx) and it is not a 401/403 (handled by AuthRequiredError) and not a JSON-parse failure, it wraps the raw HTTP status into CommandExecutionError with message `HTTP ${code}`. This is the catch-all for non-auth HTTP failures like 404, 429, 5xx.

Source

Thrown at clis/ke/utils.js:94

    const result = await page.evaluate(`(async () => {
    const res = await fetch(${JSON.stringify(url)}, { credentials: 'include' });
    if (!res.ok) return { __keErr: res.status };
    try {
      return await res.json();
    } catch {
      return { __keErr: 'parse' };
    }
  })()`);
    const r = result;
    if (r?.__keErr !== undefined) {
        const code = r.__keErr;
        if (code === 401 || code === 403) {
            throw new AuthRequiredError('ke.com', '未登录或登录已过期,请先在浏览器中登录贝壳找房');
        }
        if (code === 'parse') {
            throw new CommandExecutionError('响应不是有效 JSON', '可能触发了风控,请检查登录状态或稍后重试');
        }
        throw new CommandExecutionError(`HTTP ${code}`, '请检查网络连接或登录状态');
    }
    return result;
}

/**
 * Build a ke.com city URL prefix. Default city is 'bj' (Beijing).
 */
export function cityUrl(city) {
    return `https://${city}.ke.com`;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Read the HTTP code in the message: 429 means slow down / retry later; 404/400 means the API URL may have changed — update it; 5xx means retry after ke.com recovers
  2. Check network connectivity and that the browser session can reach ke.com at all
  3. Re-login in the browser to rule out session-related failures, then retry
  4. If persistent, verify the URL passed to fetchKeJson (city prefix, query params) is still valid

Example fix

// before
const data = await fetchKeJson(page, oldEndpoint);
// after
let data;
try {
  data = await fetchKeJson(page, newEndpoint);
} catch (e) {
  if (/HTTP 429/.test(e.message)) { await sleep(5000); data = await fetchKeJson(page, newEndpoint); }
  else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// health-check the endpoint before the real call
const probe = await page.evaluate(`fetch(${JSON.stringify(url)}, { credentials:'include', method:'HEAD' }).then(r => r.status).catch(() => 0)`);
if (probe === 429) throw new Error('rate-limited, back off before calling fetchKeJson');

Type guard

function isKeResult(r) { return r != null && typeof r === 'object' && r.__keErr === undefined; }

Try / catch

try {
  const data = await fetchKeJson(page, url);
} catch (e) {
  const m = /HTTP (\d{3})/.exec(e.message);
  if (m && Number(m[1]) === 429) { await sleep(5000); return fetchKeJson(page, url); }
  throw e; // 404/5xx: surface to caller
}

Prevention

When it happens

Trigger: Any ke.com JSON endpoint returns a non-2xx, non-401/403 status: e.g. 404 from a changed/renamed API path, 429 from rate limiting, 5xx from server errors, or 3xx followed by a non-OK terminal response.

Common situations: Ke.com rotates its internal API URLs so an old endpoint 404s; scraping too fast triggers 429 rate limiting; ke.com serves an HTML error page (5xx) during incidents; an invalid city prefix builds a bad URL.

Related errors


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