{"record":{"id":"87b5037996954746","repo":"DIYgod/RSSHub","slug":"article-api-error","errorCode":null,"errorMessage":"article api error","messagePattern":"article api error","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"error","filePath":"lib/routes/scut/jwc/news.ts","lineNumber":34,"sourceCode":"const getArticleMobileUrlById = (id) => `${baseUrl}/dist/#/detail/index?id=${id}&type=news`;\n\nconst generateArticlePubDate = (createDateStr) => {\n    const date = new Date(createDateStr);\n    date.setHours(8);\n    date.setMinutes(0);\n    date.setSeconds(0);\n    date.setMilliseconds(0);\n\n    return timezone(date, 8);\n};\n\nconst isRedirectPage = (data) => !!data.link;\n\nconst resolveRelativeUrl = (html) => html.replaceAll('src=\"/', () => `src=\"${new URL('.', baseUrl).href}`).replaceAll('href=\"/', () => `href=\"${new URL('.', baseUrl).href}`);\n\nconst apiSuccessAssert = (data) => {\n    if (!data.success) {\n        throw new Error('article api error');\n    }\n};\n\nconst generateBannerImgHtml = (bannerImageUrl) => (bannerImageUrl ? `<p><img src=\"${bannerImageUrl}\"></p>` : '');\n\nconst generateArticleLink = (id) => `<p>链接：<a href=\"${getArticleUrlById(id)}\">电脑版</a>&nbsp;|&nbsp;<a href=\"${getArticleMobileUrlById(id)}\">手机版</a></p>`;\n\nconst generateArticleFullText = (data) => generateBannerImgHtml(data.bannerUrl) + resolveRelativeUrl(data.content) + generateArticleLink(data.id);\n\nexport const route: Route = {\n    path: '/jwc/news',\n    categories: ['university'],\n    example: '/scut/jwc/news',\n    parameters: {},\n    features: {\n        requireConfig: false,\n        requirePuppeteer: false,\n        antiCrawler: true,","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/scut/jwc/news.ts#L16-L52","documentation":"The SCUT (South China University of Technology) JWC news route calls an internal article API and asserts the response with `apiSuccessAssert(data)`, which throws `'article api error'` when `data.success` is falsy. The upstream API returns `{success: true|false, ...}`; a false value typically means the article id was not found, was archived, or the backend rejected the request.","triggerScenarios":"Looping over article ids fetched from the list endpoint and calling the detail API; one id returns `{success: false}` because it was deleted, restricted, or the API is rate-limiting. The throw breaks the whole feed build, not just that item.","commonSituations":"Article removed from the official site between list fetch and detail fetch; SCUT enabled auth on certain articles; transient backend error or maintenance window.","solutions":["Retry the route after a short interval — transient upstream failures often clear.","If the error is persistent, the upstream API shape may have changed; inspect the actual response body to see whether `success` was renamed or moved.","Defensively, the handler could skip items with `success===false` instead of throwing, but that requires a code change in lib/routes/scut/jwc/news.ts."],"exampleFix":"// before\nconst apiSuccessAssert = (data) => {\n    if (!data.success) {\n        throw new Error('article api error');\n    }\n};\n\n// after (skip broken items instead of failing the whole feed)\nconst isArticleAvailable = (data) => !!data.success;","handlingStrategy":"try-catch","validationCode":"const data = await fetchArticle(id);\nif (!data?.success) {\n    // skip rather than throw\n    return null;\n}","typeGuard":"const isArticleSuccess = (d: unknown): boolean =>\n    typeof d === 'object' && d !== null && (d as any).success === true;","tryCatchPattern":"try {\n    await apiSuccessAssert(data);\n} catch (e) {\n    if (e instanceof Error && e.message === 'article api error') {\n        // skip this article, continue the feed\n        continue;\n    }\n    throw e;\n}","preventionTips":["Add a retry with backoff for transient upstream failures.","Cache the article list separately so a single detail failure does not waste the list fetch.","Consider patching apiSuccessAssert to return a sentinel instead of throwing."],"tags":["upstream-api","data-integrity","university"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}