jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP ${outcome.status}
Error message
${label} returned HTTP ${outcome.status} What it means
postJikeApi treats any HTTP status outside 2xx as an API error and throws CommandExecutionError labeled 'X returned HTTP <status>'. Non-2xx statuses that are clearly auth failures (401/403) are handled earlier as AuthRequiredError, so this branch is for other failures like 404, 429, 5xx.
Source
Thrown at clis/jike/utils.js:88
return { kind: 'response', status: response.status, body };
} catch (error) {
return { kind: 'transport', detail: String(error?.message || error) };
}
})()`);
if (outcome?.kind === 'auth' || outcome?.status === 401 || outcome?.status === 403) {
throw new AuthRequiredError('web.okjike.com', outcome?.detail || `${label} returned HTTP ${outcome?.status}`);
}
if (outcome?.kind === 'transport') {
throw new CommandExecutionError(`${label} request failed: ${outcome.detail}`);
}
if (outcome?.kind === 'json') {
throw new CommandExecutionError(`${label} returned invalid JSON: ${outcome.detail}`);
}
if (outcome?.kind !== 'response' || !Number.isInteger(outcome.status)) {
throw new CommandExecutionError(`${label} returned an unexpected response`);
}
if (outcome.status < 200 || outcome.status >= 300) {
throw new CommandExecutionError(`${label} returned HTTP ${outcome.status}`);
}
return outcome.body;
}
/**
* 注入浏览器 evaluate 的 JS 函数字符串。
* 从 React fiber 树中向上最多走 10 层,找到含 id 字段的 props.data。
*/
export const getPostDataJs = `
function getPostData(element) {
for (const key of Object.keys(element)) {
if (key.startsWith('__reactFiber$') || key.startsWith('__reactInternalInstance$')) {
let fiber = element[key];
for (let i = 0; i < 10 && fiber; i++) {
const props = fiber.memoizedProps || fiber.pendingProps;
if (props && props.data && props.data.id) return props.data;
fiber = fiber.return;
}View on GitHub (pinned to 49907e53dc)
Solutions
- Read the status in the message: 429 → back off and retry with delay; 5xx → retry later; 404 → check the endpoint path
- For 400, verify the request payload/params your code passes to the helper
- Reduce call frequency or add rate limiting between consecutive API calls
- Check jike service status / community reports if 5xx persists
- Update the CLI if the API surface has changed
Example fix
// before
const feed = await body('postJikeApi', '/api/feed');
// after
let feed;
for (let attempt = 0; attempt < 3; attempt++) {
try { feed = await body('postJikeApi', '/api/feed'); break; }
catch (err) {
if (/HTTP 429|HTTP 5\d\d/.test(err.message) && attempt < 2) { await sleep(3000 * (attempt + 1)); continue; }
throw err;
}
} Defensive patterns
Strategy: retry
Type guard
function isHttpStatusError(err, min = 400) {
const m = err instanceof CommandExecutionError && err.message.match(/returned HTTP (\d{3})/);
return m ? Number(m[1]) >= min : false;
} Try / catch
try {
const body = await body('postJikeApi', path, payload);
} catch (err) {
const m = err.message.match(/returned HTTP (\d{3})/);
if (m && (m[1] === '429' || m[1].startsWith('5'))) {
await sleep(3000); // retry once for rate-limit/server errors
} else throw err;
} Prevention
- Throttle request rate to avoid 429s
- Distinguish 4xx (fix request) from 5xx/429 (retry) in handlers
- Keep endpoint paths updated after site changes
- Add jittered backoff for retries
When it happens
Trigger: web.okjike.com returns e.g. 400 (bad request body), 404 (endpoint renamed), 429 (rate limited) or 5xx (server error) for a jike API call routed through postJikeApi.
Common situations: Hitting the API too frequently (429); jike server outage (5xx); endpoint changed after a site update (404); malformed payload/params (400).
Related errors
- toutiao hot-board failed: HTTP ${resp.status}
- toutiao recommend failed: HTTP ${resp.status}
- WeRead search page request failed: HTTP ${resp.status}
- FETCH_ERROR
- Xiaoyuzhou transcript download failed with HTTP ${response.s
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/672c2f171f52c7d3.
Report an issue: GitHub.