jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP ${resp.status}
Error message
${label} returned HTTP ${resp.status} What it means
After the 429 check, juejinFetch requires `resp.ok` (2xx). Any other HTTP status (403, 404, 5xx, etc.) is thrown as a CommandExecutionError carrying the status code. Unlike 429 it has no remediation hint, because the meaning depends entirely on the endpoint and status.
Source
Thrown at clis/juejin/utils.js:111
if (method === 'POST') {
init.headers['content-type'] = 'application/json';
init.body = JSON.stringify(body ?? {});
}
resp = await fetch(url, init);
} catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that api.juejin.cn is reachable from this network.',
);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'Juejin throttles bursty traffic; wait a few seconds and retry.',
);
}
if (!resp.ok) {
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
}
let payload;
try {
payload = await resp.json();
} catch (err) {
throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
}
if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'err_no')) {
throw new CommandExecutionError(`${label} returned a malformed API envelope`);
}
if (payload.err_no !== 0) {
throw new CommandExecutionError(`${label} returned err_no ${payload.err_no}: ${payload.err_msg ?? ''}`);
}
return payload;
}
export function readDataArray(payload, label) {
if (!payload || typeof payload !== 'object' || Array.isArray(payload) || !Object.hasOwn(payload, 'data')) {View on GitHub (pinned to 49907e53dc)
Solutions
- Check the status in the message: 403/405 usually means WAF blocking — try from a residential IP or adjust the user-agent.
- For 5xx, treat it as a transient Juejin outage: retry after a minute; check Juejin's status.
- For 404, verify the endpoint path in the calling adapter code hasn't been retired by a Juejin API change; update the path.
- Confirm JUEJIN_API_BASE is unchanged and correct (https://api.juejin.cn).
- Reproduce with `curl -X POST -H 'content-type: application/json' -d '{}' <url>` to see the raw status/body and any WAF challenge page.
Example fix
// before
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
// after (caller handles transient 5xx with backoff)
try {
const payload = await juejinFetch('/recommend_api/feed/v1', body, 'juejin recommend');
} catch (e) {
if (/HTTP 5\d\d/.test(e.message)) await sleep(5000), retry();
else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// optional pre-flight endpoint sanity check
async function endpointOk(path) {
try {
const r = await fetch(`https://api.juejin.cn${path}`, {
method: 'POST', headers: { 'content-type': 'application/json' }, body: '{}',
signal: AbortSignal.timeout(5000),
});
return r.status !== 404 && r.status !== 405; // path still exists
} catch { return false; }
} Type guard
function isHttpStatusError(err) {
const m = err instanceof CommandExecutionError && err.message.match(/returned HTTP (\d{3})/);
return m ? { isMatch: true, status: Number(m[1]) } : { isMatch: false, status: null };
} Try / catch
try {
const payload = await juejinFetch(path, body, label);
} catch (err) {
const { isMatch, status } = isHttpStatusError(err);
if (isMatch && status >= 500) {
console.error('Juejin server error — retry later.');
} else if (isMatch && (status === 403 || status === 405)) {
console.error('Blocked or unsupported request — check egress IP / adapter version.');
} else {
throw err;
}
} Prevention
- Classify statuses in your catch block: 5xx retry, 4xx (403/404) investigate config or adapter version.
- Pin and periodically update the adapter — Juejin endpoint paths can change without notice.
- Reproduce odd statuses with curl against the same URL/headers to see WAF challenge bodies.
- Avoid datacenter-only egress IPs for Juejin; they attract WAF 403s.
When it happens
Trigger: api.juejin.cn returned a non-ok, non-429 status to a juejinFetch call: e.g. 403 from a WAF/anti-bot layer, 404 from a changed/retired endpoint path, 5xx from a Juejin server-side outage, or 301/30x mishandling if the API surface moved.
Common situations: Juejin's WAF returning 403 to datacenter/VPN IPs; the adapter's endpoint path breaking after a Juejin API redesign; transient 502/503 during Juejin deploy windows; wrong JUEJIN_API_BASE if someone points it at a mirror.
Related errors
- 1point3acres request failed: HTTP ${res.status} ${res.status
- ${label} returned HTTP ${resp.status} (${url})
- coingecko derivatives returned HTTP ${resp.status}
- ${label} returned HTTP ${outcome.status}
- HTTP ${probe.httpStatus} from Jimeng passport
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/039650fe1479d8c2.
Report an issue: GitHub.