{"record":{"id":"bd7037ff54b65921","repo":"jackwener/OpenCLI","slug":"parsed-message-parsed-msg-xiaoyuzhou-ap","errorCode":null,"errorMessage":"${parsed?.message || parsed?.msg || `Xiaoyuzhou API returned service code ${numericCode}`}","messagePattern":"\\$\\{parsed\\?\\.message \\|\\| parsed\\?\\.msg \\|\\| `Xiaoyuzhou API returned service code \\$\\{numericCode\\}`\\}","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaoyuzhou/auth.js","lineNumber":246,"sourceCode":"        parsed = JSON.parse(bodyText);\n    }\n    catch (error) {\n        throw new CommandExecutionError(`Xiaoyuzhou API returned invalid JSON: ${getErrorMessage(error)}`);\n    }\n    const serviceCode = parsed?.code;\n    if (serviceCode !== undefined && serviceCode !== null) {\n        const numericCode = Number(serviceCode);\n        if (!Number.isFinite(numericCode)) {\n            throw new CommandExecutionError('Xiaoyuzhou API returned an invalid service code');\n        }\n        if (numericCode === 401 || numericCode === 403) {\n            throw createXiaoyuzhouAuthError(`Xiaoyuzhou API rejected the credentials with service code ${numericCode}`);\n        }\n        if (numericCode !== 0 && numericCode !== 200) {\n            throw new CommandExecutionError(\n                parsed?.message || parsed?.msg || `Xiaoyuzhou API returned service code ${numericCode}`,\n            );\n        }\n    }\n    if (parsed?.success === false) {\n        throw new CommandExecutionError(parsed?.message || parsed?.msg || 'Xiaoyuzhou API returned success=false');\n    }\n    return {\n        credentials,\n        raw: parsed,\n        data: parsed?.data,\n    };\n}\n\nexport async function fetchXiaoyuzhouTranscriptBody(url, fetchImpl = fetch) {\n    let response;\n    try {\n        response = await fetchImpl(url, {\n            method: 'GET',\n            headers: {\n                'User-Agent': XIAOYUZHOU_DEFAULT_USER_AGENT,","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaoyuzhou/auth.js#L228-L264","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: one generic retry for all codes\nconst data = await requestXiaoyuzhouJson(creds, path, params);\n// after: retry only transient codes\ntry {\n  data = await requestXiaoyuzhouJson(creds, path, params);\n} catch (e) {\n  if (/code (429|5\\d\\d)/.test(e.message)) {\n    await sleep(backoff);\n    data = await requestXiaoyuzhouJson(creds, path, params);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// validate inputs the API would 404/400 on before calling\nif (!episodeId || !/^[A-Za-z0-9-]+$/.test(episodeId)) {\n  throw new Error(`Invalid episodeId: ${episodeId}`);\n}","typeGuard":"function isTransientServiceCode(e) {\n  const m = e.message.match(/service code (\\d+)/);\n  if (!m) return /code (429|5\\d\\d)/.test(e.message);\n  const code = Number(m[1]);\n  return code === 429 || code >= 500;\n}","tryCatchPattern":"for (let attempt = 0; attempt < 3; attempt++) {\n  try {\n    return await requestXiaoyuzhouJson(creds, path, params);\n  } catch (e) {\n    if (isTransientServiceCode(e) && attempt < 2) {\n      await new Promise(r => setTimeout(r, 2 ** attempt * 1000)); // backoff: 1s, 2s\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["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."],"tags":["api-response","service-error","http-status","rate-limit"],"backgroundTag":"api-error-code-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}