jackwener/OpenCLI · error · CommandExecutionError
http
Error message
http
What it means
verifyXueqiuIdentity probes the xueqiu stock API inside the browser to confirm the session is logged in. When the probe reports kind 'http' (any non-OK HTTP status, notably 403 anti-bot/rate limit), it wraps the result into a CommandExecutionError with the status and detail. It signals the site rejected the authenticated API request at the HTTP layer rather than via an auth envelope.
Source
Thrown at clis/xueqiu/auth.js:43
const d = await res.json();
if (d?.error_code === 60201) {
return { kind: 'auth', detail: 'xueqiu portfolio API error_code 60201 用户id无效 — anonymous' };
}
if (d?.error_code) {
return { kind: 'xq-error', errorCode: d.error_code, detail: d.error_description || 'xueqiu API error' };
}
const uCookie = document.cookie.split('; ').find(c => c.startsWith('u='))?.split('=')[1] || '';
const cookiesuCookie = document.cookie.split('; ').find(c => c.startsWith('cookiesu='))?.split('=')[1] || '';
if (!uCookie || uCookie === cookiesuCookie) {
return { kind: 'auth', detail: 'xueqiu u cookie equals cookiesu (device id) — anonymous despite portfolio API 200' };
}
return { ok: true, user_id: uCookie };
} catch (e) {
return { kind: 'exception', detail: String(e && e.message || e) };
}
})()`);
if (probe?.kind === 'auth') throw new AuthRequiredError('xueqiu.com', probe.detail);
if (probe?.kind === 'http') throw new CommandExecutionError(`HTTP ${probe.httpStatus} from xueqiu stock API: ${probe.detail || ''}`);
if (probe?.kind === 'xq-error') throw new CommandExecutionError(`xueqiu API error_code ${probe.errorCode}: ${probe.detail}`);
if (probe?.kind === 'exception') throw new CommandExecutionError(`xueqiu whoami failed: ${probe.detail}`);
if (!probe?.ok) throw new CommandExecutionError(`Unexpected xueqiu probe: ${JSON.stringify(probe)}`);
return { user_id: String(probe.user_id) };
}
registerSiteAuthCommands({
site: 'xueqiu',
domain: 'xueqiu.com',
loginUrl: 'https://xueqiu.com/',
columns: ['user_id'],
quickCheck: hasXueqiuAccessToken,
verify: verifyXueqiuIdentity,
poll: async (page) => {
if (!await hasXueqiuAccessToken(page)) {
throw new AuthRequiredError('xueqiu.com', 'Waiting for Xueqiu xq_a_token cookie');
}
return verifyXueqiuIdentity(page);View on GitHub (pinned to 49907e53dc)
Solutions
- Wait and back off, then retry — 403 usually means anti-bot or rate limiting
- Open https://xueqiu.com/ in the automation browser, complete any captcha/challenge, and re-login so xq_a_token and u cookies are fresh
- Re-run the verify command with --verbose to see the full HTTP status and detail
- If a non-403 status persists (e.g. 404), check whether xueqiu changed the portfolio API endpoint
Example fix
// before (retrying immediately in a loop) await verifyXueqiuIdentity(page); // after (back off on 403 before retrying) await new Promise(r => setTimeout(r, 5000)); await verifyXueqiuIdentity(page);
Defensive patterns
Strategy: retry
Validate before calling
const cookies = await page.getCookies({ url: 'https://xueqiu.com' });
const hasToken = cookies.some(c => c.name === 'xq_a_token' && c.value);
if (!hasToken) throw new Error('Login to xueqiu first: xq_a_token cookie missing'); Type guard
function isHttpProbe(p) {
return !!p && typeof p === 'object' && p.kind === 'http' && typeof p.httpStatus === 'number';
} Try / catch
try {
await verifyXueqiuIdentity(page);
} catch (e) {
if (/HTTP 403/.test(e.message)) {
await new Promise(r => setTimeout(r, 10_000)); // back off anti-bot
await verifyXueqiuIdentity(page);
} else throw e;
} Prevention
- Always complete xueqiu login before running verify or data commands
- Space out verify calls to avoid triggering Aliyun WAF rate limits
- Run with --verbose when diagnosing so the HTTP status and detail are visible
- Keep the automation browser on xueqiu.com and solve any captcha promptly
When it happens
Trigger: Running the xueqiu auth verify flow when the in-page fetch to https://stock.xueqiu.com/v5/stock/portfolio/stock/list.json returns a non-2xx status: res.status === 403 (anti-bot / rate limit) or any other !res.ok status.
Common situations: Hitting xueqiu's Aliyun WAF/rate limiter after too many rapid verify calls; a logged-out or stale session that gets 403 instead of a JSON error envelope; xueqiu changing the portfolio endpoint so it returns 404/5xx.
Related errors
- toutiao hot-board failed: HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- 12306 ${endpoint} returned non-JSON body
- autohome ${contextHint} HTTP ${resp.status}
- Chess.com callback returned HTTP ${resp.status} for ${url}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c27f5678c186fd5e.
Report an issue: GitHub.