jackwener/OpenCLI · error · CommandExecutionError
${parsed?.message || parsed?.msg || `Xiaoyuzhou API returned
Error message
${parsed?.message || parsed?.msg || `Xiaoyuzhou API returned service code ${numericCode}`} What it means
For any parsed service code other than 0, 200, 401, or 403, requestXiaoyuzhouJson throws a CommandExecutionError using the API's own message field (parsed.message or parsed.msg), falling back to a generic code report. This surfaces backend-declared failures (business logic or server errors) to the CLI user.
Source
Thrown at clis/xiaoyuzhou/auth.js:246
parsed = JSON.parse(bodyText);
}
catch (error) {
throw new CommandExecutionError(`Xiaoyuzhou API returned invalid JSON: ${getErrorMessage(error)}`);
}
const serviceCode = parsed?.code;
if (serviceCode !== undefined && serviceCode !== null) {
const numericCode = Number(serviceCode);
if (!Number.isFinite(numericCode)) {
throw new CommandExecutionError('Xiaoyuzhou API returned an invalid service code');
}
if (numericCode === 401 || numericCode === 403) {
throw createXiaoyuzhouAuthError(`Xiaoyuzhou API rejected the credentials with service code ${numericCode}`);
}
if (numericCode !== 0 && numericCode !== 200) {
throw new CommandExecutionError(
parsed?.message || parsed?.msg || `Xiaoyuzhou API returned service code ${numericCode}`,
);
}
}
if (parsed?.success === false) {
throw new CommandExecutionError(parsed?.message || parsed?.msg || 'Xiaoyuzhou API returned success=false');
}
return {
credentials,
raw: parsed,
data: parsed?.data,
};
}
export async function fetchXiaoyuzhouTranscriptBody(url, fetchImpl = fetch) {
let response;
try {
response = await fetchImpl(url, {
method: 'GET',
headers: {
'User-Agent': XIAOYUZHOU_DEFAULT_USER_AGENT,View on GitHub (pinned to 49907e53dc)
Solutions
- Read the message field in the error — it comes straight from the API and usually names the actual problem (e.g. not found vs rate limited).
- For 404: verify the episode/podcast/feed ID passed by the calling command is correct.
- For 429: back off and retry with exponential delay; reduce polling frequency.
- For 5xx: retry later; check Xiaoyuzhou service status.
- If a new code appears repeatedly, extend requestXiaoyuzhouJson to handle it explicitly.
Example fix
// before: one generic retry for all codes
const data = await requestXiaoyuzhouJson(creds, path, params);
// after: retry only transient codes
try {
data = await requestXiaoyuzhouJson(creds, path, params);
} catch (e) {
if (/code (429|5\d\d)/.test(e.message)) {
await sleep(backoff);
data = await requestXiaoyuzhouJson(creds, path, params);
} else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// validate inputs the API would 404/400 on before calling
if (!episodeId || !/^[A-Za-z0-9-]+$/.test(episodeId)) {
throw new Error(`Invalid episodeId: ${episodeId}`);
} Type guard
function isTransientServiceCode(e) {
const m = e.message.match(/service code (\d+)/);
if (!m) return /code (429|5\d\d)/.test(e.message);
const code = Number(m[1]);
return code === 429 || code >= 500;
} Try / catch
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await requestXiaoyuzhouJson(creds, path, params);
} catch (e) {
if (isTransientServiceCode(e) && attempt < 2) {
await new Promise(r => setTimeout(r, 2 ** attempt * 1000)); // backoff: 1s, 2s
continue;
}
throw e;
}
} Prevention
- Validate resource IDs before sending requests to avoid 404-class codes.
- Throttle request rate and add backoff to avoid 429s.
- Distinguish retryable (429/5xx) from permanent (4xx) codes before retrying.
- Monitor the API's message field — it names the real failure cause.
- Add unit tests covering the code values your CLI special-cases.
When it happens
Trigger: parsed.code is a finite number not in {0, 200, 401, 403} — e.g. 404 (unknown episode/podcast id), 429 (rate limited), 5xx (server error) reported inside the JSON envelope by the Xiaoyuzhou backend.
Common situations: Requesting a deleted or wrong episode/podcast ID (404); hitting rate limits after rapid polling (429); upstream Xiaoyuzhou outages returning 500-class codes; API contract changes introducing new code values the CLI doesn't special-case.
Related errors
- archive snapshots failed: HTTP ${resp.status}
- DuckDuckGo suggest returned HTTP ${resp.status}
- Instagram private publish ${stage} failed: ${response.status
- Instagram returned non-ok status: ${JSON.stringify(d).slice(
- Failed to fetch followers: HTTP ' + r2.status
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/bd7037ff54b65921.
Report an issue: GitHub.