{"record":{"id":"719a7d00080b4068","repo":"DIYgod/RSSHub","slug":"api-error","errorCode":null,"errorMessage":"api error","messagePattern":"api error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/routes/bt0/util.ts","lineNumber":19,"sourceCode":"import { CookieJar } from 'tough-cookie';\n\nimport got from '@/utils/got';\n\nconst cookieJar = new CookieJar();\n\nasync function doGot(num, host, link) {\n    if (num > 4) {\n        throw new Error('The number of attempts has exceeded 5 times');\n    }\n    const response = await got.get(link, {\n        cookieJar,\n    });\n    const data = response.data;\n    if (typeof data === 'string') {\n        const regex = /document\\.cookie\\s*=\\s*\"([^\"]*)\"/;\n        const match = data.match(regex);\n        if (!match) {\n            throw new Error('api error');\n        }\n        cookieJar.setCookieSync(match[1], host);\n        return doGot(num + 1, host, link);\n    }\n    return data;\n}\n\nconst genSize = (sizeStr) => {\n    // 正则表达式，用于匹配数字和单位 GB 或 MB\n    const regex = /^(\\d+(\\.\\d+)?)\\s*(gb|mb)$/i;\n    const match = sizeStr.match(regex);\n\n    if (!match) {\n        return 0;\n    }\n\n    const value = Number(match[1]);\n    const unit = match[3].toUpperCase();","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/DIYgod/RSSHub/blob/bed535e0879dc71c5aff6f1e7bd1ac21ede40115/lib/routes/bt0/util.ts#L1-L37","documentation":"Generic Error thrown inside doGot when the response body is a string (i.e. an HTML challenge page, not the expected JSON) but the regex /document\\.cookie\\s*=\\s*\"([^\"]*)\"/ finds no match. It means the server returned an HTML page whose cookie-setting syntax the helper cannot parse, so it cannot proceed with the challenge.","triggerScenarios":"response.data is a string (HTML) but contains no `document.cookie=\"...\"` assignment — e.g. the anti-bot page changed to set cookies via a function call, a meta tag, or no cookie at all (a hard block / maintenance page).","commonSituations":"bt0 updated its anti-bot template; the page is a hard 403/captcha instead of a JS cookie challenge; an intermediate proxy rewrote the HTML.","solutions":["Fetch the same URL with curl/the helper's cookieJar and inspect the HTML to see how the cookie is now set; update the regex accordingly.","If the page is a captcha/hard block, the IP is likely banned — route through a different egress or retry later.","Confirm the endpoint URL (_link in mv.ts/tlist.ts) still returns the challenge and not a 404."],"exampleFix":"// before\nif (!match) {\n    throw new Error('api error');\n}\n// after (include a snippet for diagnosis)\nif (!match) {\n    throw new Error(`bt0 api error: HTML challenge has no document.cookie match (first 200 chars: ${data.slice(0, 200)})`);\n}","handlingStrategy":"retry","validationCode":"if (typeof data === 'string') {\n    const match = data.match(/document\\.cookie\\s*=\\s*\"([^\"]*)\"/);\n    if (!match) throw new Error(`bt0 api error: no document.cookie match in HTML (len ${data.length})`);\n    cookieJar.setCookieSync(match[1], host);\n    return doGot(num + 1, host, link);\n}","typeGuard":"const isCookieChallengeHtml = (s: string): boolean =>\n    /document\\.cookie\\s*=\\s*\"[^\"]*\"/.test(s);","tryCatchPattern":"// If the regex misses once, retry the raw fetch — the challenge page can be intermittent:\nlet body = await got.get(link, { cookieJar });\nif (typeof body.data === 'string' && !isCookieChallengeHtml(body.data)) {\n    // one fresh attempt before failing\n    body = await got.get(link, { cookieJar });\n}","preventionTips":["Log a snippet of the HTML when the regex misses to detect template changes.","Update the regex promptly when bt0 changes its cookie-set syntax.","Distinguish a hard block (captcha/403) from a parseable challenge."],"tags":["bt0","anti-crawl","regex","html-parsing","diagnostics"],"backgroundTag":null,"analyzedSha":"bed535e0879dc71c5aff6f1e7bd1ac21ede40115","analyzedAt":"2026-08-12T19:29:35.364Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}