jackwener/OpenCLI · error · CommandExecutionError

toutiao hot-board returned status=${payload.status}

Error message

toutiao hot-board returned status=${payload.status}

What it means

After parsing, the command checks payload.status; if the hot-board JSON reports a status other than 'success' this CommandExecutionError is thrown with the reported value. It means the API responded with valid JSON but signalled an application-level failure (e.g. status='error', 'fail', or a code string).

Source

Thrown at clis/toutiao/hot.js:50

                    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
                    Accept: 'application/json',
                    Referer: 'https://www.toutiao.com/',
                },
            });
        } catch (error) {
            throw new CommandExecutionError(`toutiao hot-board request failed: ${error?.message || error}`);
        }
        if (!resp.ok) {
            throw new CommandExecutionError(`toutiao hot-board failed: HTTP ${resp.status}`);
        }
        let payload;
        try {
            payload = await resp.json();
        } catch (error) {
            throw new CommandExecutionError(`toutiao hot-board returned malformed JSON: ${error?.message || error}`);
        }
        if (payload?.status && payload.status !== 'success') {
            throw new CommandExecutionError(`toutiao hot-board returned status=${payload.status}`);
        }
        if (payload?.error || payload?.message) {
            throw new CommandExecutionError(`toutiao hot-board returned error: ${payload.error || payload.message}`);
        }
        const list = Array.isArray(payload?.data) ? payload.data : [];
        const rows = list.map(mapHotRow).filter(Boolean).slice(0, limit);
        if (rows.length === 0) {
            throw new EmptyResultError('toutiao hot', '上游 hot-board 返回空列表。');
        }
        // Re-rank (1..N) after filter so ranks are dense even if upstream had nulls.
        return rows.map((row, idx) => ({ ...row, rank: idx + 1 }));
    },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the full payload to see the exact status value and any accompanying message field.
  2. Check the payload.message/error fields (the next check throws on those) for the upstream reason; retry if transient.
  3. Compare the current live response from the endpoint with what this code expects and update the status check / mapping if Toutiao changed the contract.
  4. If the endpoint is in maintenance, wait and retry later.

Example fix

// before
if (payload?.status && payload.status !== 'success') {
  throw new CommandExecutionError(`toutiao hot-board returned status=${payload.status}`);
}
// after — tolerate numeric success codes
const ok = payload?.status === 'success' || payload?.status === 0 || payload?.status === '0';
if (payload?.status !== undefined && !ok) {
  throw new CommandExecutionError(`toutiao hot-board returned status=${payload.status}`);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// validate the envelope shape before trusting the data
const isHotBoardPayload = (p) =>
  p && typeof p === 'object' &&
  (p.status === undefined || p.status === 'success') &&
  (p.data === undefined || Array.isArray(p.data));

Type guard

function isHotBoardPayload(p) {
  return (
    p !== null && typeof p === 'object' &&
    ('status' in p ? p.status === 'success' : true) &&
    ('data' in p ? Array.isArray(p.data) : true)
  );
}

Try / catch

try {
  const rows = await toutiaoHot({ limit: 30 });
} catch (e) {
  if (/returned status=/.test(e.message)) {
    // application-level upstream failure: inspect payload, wait, retry
    await sleep(5000);
    return toutiaoHot({ limit: 30 });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `toutiao hot` when Toutiao's endpoint returns a JSON envelope like {status:'error'} due to server-side throttling, maintenance, or a changed response contract (status field renamed/repurposed).

Common situations: Upstream API partially failing while still returning 200; Toutiao changing the response schema so status now carries a numeric code; regional restrictions returning a denial envelope.

Related errors


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