{"record":{"id":"4a52fe32fa059dc6","repo":"DIYgod/RSSHub","slug":"invalid-username-or-email-or-password-for-nhenta","errorCode":null,"errorMessage":"Invalid username (or email) or password for nhentai torrent download","messagePattern":"Invalid username \\(or email\\) or password for nhentai torrent download","errorType":"validation","errorClass":"ConfigNotFoundError","httpStatus":null,"severity":"error","filePath":"lib/routes/nhentai/util.tsx","lineNumber":110,"sourceCode":"\nconst getSimple = async (url) => {\n    const data = await fetchPage(url);\n    const $ = load(data);\n\n    return $('.gallery a.cover')\n        .toArray()\n        .map((ele) => parseSimpleDetail($(ele)));\n};\n\nconst getDetails = (cache, simples, limit) => Promise.all(simples.slice(0, limit).map((simple) => cache.tryGet(simple.link, () => getDetail(simple))));\n\nconst getTorrents = async (cache, simples, limit) => {\n    if (!config.nhentai || !config.nhentai.username || !config.nhentai.password) {\n        throw new ConfigNotFoundError('nhentai RSS with torrents is disabled due to the lack of <a href=\"https://docs.rsshub.app/deploy/config#route-specific-configurations\">relevant config</a>');\n    }\n    const cookie = await getCookie(config.nhentai.username, config.nhentai.password, cache);\n    if (!cookie) {\n        throw new ConfigNotFoundError('Invalid username (or email) or password for nhentai torrent download');\n    }\n    return getTorrentWithCookie(cache, simples, cookie, limit);\n};\nconst getTorrentWithCookie = (cache, simples, cookie, limit) => Promise.all(simples.slice(0, limit).map((simple) => cache.tryGet(simple.link + 'download', () => getTorrent(simple, cookie))));\n\nconst parseSimpleDetail = ($ele) => {\n    const link = new URL($ele.attr('href'), baseUrl).href;\n    const thumb = $ele.children('img');\n    const thumbSrc = thumb.attr('data-src') || thumb.attr('src');\n    const highResoThumbSrc = thumbSrc\n        .replace('thumb', '1')\n        .replace(/t(\\d+)\\.nhentai\\.net/, 'i$1.nhentai.net')\n        .replace('.webp.webp', '.webp');\n    return {\n        title: $ele.children('.caption').text(),\n        link,\n        description: `<img src=\"${highResoThumbSrc}\">`,\n    };","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/nhentai/util.tsx#L92-L128","documentation":"A ConfigNotFoundError thrown after the nhentai login flow completes but yields no session cookie. getCookie POSTs credentials and treats a non-302 response as auth failure, caching an empty cookie string; getTorrents then re-throws it as a config error so operators know the stored credentials are wrong rather than missing.","triggerScenarios":"getCookie posts to https://nhentai.net/login/ with the configured username/password and the login response status is not 302 (redirect on success), so an empty cookie is cached and returned. The next check `if (!cookie)` triggers the error.","commonSituations":"NHENTAI_PASSWORD is stale/wrong; the account is locked or flagged; nhentai changed its CSRF/cookie scheme so the parsed csrfmiddlewaretoken or set-cookie headers are malformed (got() would then throw earlier, but a login that returns 200 with a login-failed page yields the empty-cookie path); the cached empty cookie (key 'nhentai:cookie') is still within its 3-day TTL and masks a corrected password until it expires.","solutions":["Verify NHENTAI_USERNAME/NHENTAI_PASSWORD by logging in manually at https://nhentai.net/login/.","Clear the cached bad cookie (redis/redis-like cache key 'nhentai:cookie') so the next request re-attempts login with the corrected credentials.","If credentials are correct but login still returns non-302, inspect the login response shape — the csrfmiddlewaretoken regex or set-cookie parsing in getCookie may need updating after an upstream change.","Rotate the password if the account was compromised or rate-limited."],"exampleFix":"// before\nif (!cookie) {\n    throw new ConfigNotFoundError('Invalid username (or email) or password for nhentai torrent download');\n}\n\n// after — operational fix: purge the stale bad-cookie cache entry, then let it re-login\n// redis-cli DEL nhentai:cookie   (or your cache backend equivalent)","handlingStrategy":"retry","validationCode":"// Validate credentials reachability before relying on the cookie cache.\nasync function nhentaiLoginWorks(): Promise<boolean> {\n    if (!config.nhentai?.username || !config.nhentai?.password) return false;\n    // attempt a fresh login (bypass cache) once on startup/config-change\n    const cookie = await getCookie(config.nhentai.username, config.nhentai.password, cache);\n    return Boolean(cookie);\n}","typeGuard":"const isNonEmptyCookie = (c: unknown): c is string => typeof c === 'string' && c.length > 0;","tryCatchPattern":"try {\n    items = await getTorrents(cache, simples, limit);\n} catch (e) {\n    if (e instanceof ConfigNotFoundError && /Invalid username/.test(e.message)) {\n        // purge the cached bad cookie and retry once with fresh login\n        await cache.set('nhentai:cookie', '');\n        items = await getTorrents(cache, simples, limit); // single retry\n    } else {\n        throw e;\n    }\n}","preventionTips":["Purge the 'nhentai:cookie' cache key whenever credentials are rotated.","Do not cache an empty cookie for the full 3-day TTL — cache it briefly so corrected creds take effect sooner.","Alert on repeated login failures to catch upstream login-flow changes early."],"tags":["auth","credentials","config-not-found","cache","login"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}