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

  1. Read the status in the message: 429 → back off and retry with delay; 5xx → retry later; 404 → check the endpoint path
  2. For 400, verify the request payload/params your code passes to the helper
  3. Reduce call frequency or add rate limiting between consecutive API calls
  4. Check jike service status / community reports if 5xx persists
  5. 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

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


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