{"record":{"id":"7f3d8b9d4f9abbf6","repo":"DIYgod/RSSHub","slug":"no-novels-found-for-this-user-or-is-an-r18-creato","errorCode":null,"errorMessage":"No novels found for this user, or is an R18 creator, fallback to ConfigNotFoundError","messagePattern":"No novels found for this user, or is an R18 creator, fallback to ConfigNotFoundError","errorType":"exception","errorClass":"Error","httpStatus":503,"severity":"warning","filePath":"lib/routes/pixiv/novel-api/user-novels/sfw.ts","lineNumber":23,"sourceCode":"import { getSFWNovelContent } from '../content/sfw';\nimport type { NovelList, SFWNovelsResponse } from './types';\n\nconst baseUrl = 'https://www.pixiv.net';\n\nexport async function getSFWUserNovels(id: string, fullContent: boolean = false, limit: number = 100): Promise<NovelList> {\n    const url = `${baseUrl}/users/${id}/novels`;\n    const { data: allData } = await got(`${baseUrl}/ajax/user/${id}/profile/all`, {\n        headers: {\n            referer: url,\n        },\n    });\n\n    const novels = Object.keys(allData.body.novels)\n        .toSorted((a, b) => Number(b) - Number(a))\n        .slice(0, Number(String(limit)));\n\n    if (novels.length === 0) {\n        throw new Error('No novels found for this user, or is an R18 creator, fallback to ConfigNotFoundError');\n    }\n\n    const searchParams = new URLSearchParams();\n    for (const novel of novels) {\n        searchParams.append('ids[]', novel);\n    }\n\n    const { data } = (await got(`${baseUrl}/ajax/user/${id}/profile/novels`, {\n        headers: {\n            referer: url,\n        },\n        searchParams,\n    })) as SFWNovelsResponse;\n\n    const items = await Promise.all(\n        Object.values(data.body.works).map(async (item) => {\n            const baseItem = {\n                title: item.title,","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/pixiv/novel-api/user-novels/sfw.ts#L5-L41","documentation":"Plain Error thrown by the SFW (unauthenticated) user-novels path when /ajax/user/{id}/profile/all returns no novel keys. It is deliberately a generic Error (name 'Error'), not ConfigNotFoundError, so the novels.ts handler can catch it by error.name and fall back to the NSFW path. The message explicitly says it is a fallback signal.","triggerScenarios":"The user has no SFW-visible novels; the user is an R18 creator whose works only appear via the authenticated app API; the profile/all endpoint returned an empty novels object for a valid account.","commonSituations":"Operator has not configured PIXIV_REFRESHTOKEN and requests an R18-only author; brand-new account with no novels; account that deleted all public works.","solutions":["If the author is R18, set PIXIV_REFRESHTOKEN so the NSFW path is used (the novels handler auto-detects this Error and tries NSFW).","Confirm the user ID is valid and the account has novels on pixiv.","If configuring the token is not an option, accept that R18-only authors cannot be served by the SFW path.","Do not surface this raw message to end users; it is internal control flow."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// SFW path may legitimately return zero novels; pre-validate only the ID shape.\nfunction isValidPixivUserId(id: string): boolean {\n  return /^\\d+$/.test(id);\n}\nif (!isValidPixivUserId(id)) {\n  // reject before hitting profile/all\n}","typeGuard":"const isEmptyNovelProfile = (d: any): boolean =>\n  d && d.body && (!d.body.novels || Object.keys(d.body.novels).length === 0);","tryCatchPattern":"// this Error is intentional control flow in novels.ts:\ntry {\n  nonR18Result = await getSFWUserNovels(id, fullContent, limit);\n} catch (error: any) {\n  if (error.name !== 'Error') throw error; // only swallow the generic SFW-empty signal\n  nonR18Result = null;\n}","preventionTips":["Recognize this as an internal fallback signal, not a hard failure.","Only swallow errors whose name is 'Error' from the SFW path; rethrow others.","Pair the SFW attempt with an NSFW fallback when auth is available."],"tags":["pixiv","novel","control-flow","nsfw","fallback"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}