{"record":{"id":"616e9760f62cc89f","repo":"DIYgod/RSSHub","slug":"failed-to-get-series-data","errorCode":null,"errorMessage":"Failed to get series data","messagePattern":"Failed to get series data","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/routes/pixiv/novel-api/series/sfw.ts","lineNumber":28,"sourceCode":"\nexport async function getSFWSeriesNovels(seriesId: string, limit: number = 10): Promise<SeriesFeed> {\n    const seriesPage = await got(`${baseUrl}/novel/series/${seriesId}`);\n    const $ = load(seriesPage.data);\n\n    const title = $('meta[property=\"og:title\"]').attr('content') || '';\n    const description = $('meta[property=\"og:description\"]').attr('content') || '';\n    const image = $('meta[property=\"og:image\"]').attr('content') || '';\n\n    const response = await got(`${baseUrl}/ajax/novel/series/${seriesId}/content_titles`, {\n        headers: {\n            referer: `${baseUrl}/novel/series/${seriesId}`,\n        },\n    });\n\n    const data = response.data as SeriesContentResponse;\n\n    if (data.error) {\n        throw new Error(data.message || 'Failed to get series data');\n    }\n\n    const chapters = data.body.slice(-Math.abs(limit));\n    const chapterStartNum = Math.max(data.body.length - limit + 1, 1);\n\n    const items = await Promise.all(\n        chapters\n            .map(async (chapter, index) => {\n                if (!chapter.available) {\n                    return {\n                        title: `#${chapterStartNum + index} ${chapter.title}`,\n                        description: 'PIXIV_REFRESHTOKEN is required to view the full content.<br>需要 PIXIV_REFRESHTOKEN 才能查看完整內文。',\n                        link: `${baseUrl}/novel/show.php?id=${chapter.id}`,\n                    };\n                }\n\n                const novelContent = await getSFWNovelContent(chapter.id);\n                return {","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/pixiv/novel-api/series/sfw.ts#L10-L46","documentation":"Thrown by the SFW (unauthenticated) novel series path when pixiv's /ajax/novel/series/{seriesId}/content_titles endpoint returns a body with data.error truthy. It re-throws pixiv's own data.message, falling back to 'Failed to get series data' when pixiv omits a message. This is a plain Error (not ConfigNotFoundError or InvalidParameterError), so upstream callers treat it as a generic failure.","triggerScenarios":"seriesId does not exist, was deleted by the author, or is private/age-gated; pixiv AJAX returned HTTP 200 with an error JSON payload; transient pixiv server-side error surfacing through the error field.","commonSituations":"Series ID typo copied from the wrong URL; series removed since the feed was last fetched; an R18-only series requested through the SFW path that cannot list its chapters without login.","solutions":["Open https://www.pixiv.net/novel/series/{seriesId} in a browser to confirm the series still exists and is public.","If the series is R18, switch to the NSFW series route with a configured PIXIV_REFRESHTOKEN.","Verify the seriesId is numeric and matches the URL path segment, not the work ID.","Retry once to rule out a transient pixiv AJAX error."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"function isValidSeriesId(id: string): boolean {\n  return /^\\d+$/.test(id);\n}\n// before calling the SFW series fetch:\nif (!isValidSeriesId(seriesId)) {\n  // reject early with an invalid-parameter style message\n}","typeGuard":"const isSeriesErrorResponse = (d: unknown): d is { error: true; message?: string } =>\n  typeof d === 'object' && d !== null && (d as any).error === true;","tryCatchPattern":"try {\n  return await getSFWSeriesNovels(seriesId, limit);\n} catch (e) {\n  // plain Error from pixiv AJAX; distinguish from ConfigNotFoundError before surfacing\n  if (!(e instanceof Error) || e.name !== 'Error') throw e;\n  // series missing/private/age-gated: report to user, optionally try NSFW path\n}","preventionTips":["Validate seriesId is numeric before the AJAX call.","Treat a data.error payload as a missing/private series, not a code bug.","Offer an NSFW fallback for series that may be age-gated."],"tags":["pixiv","api","novel","series","upstream"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}