{"record":{"id":"4fe05659e40b2e3e","repo":"jackwener/OpenCLI","slug":"tieba-did-not-land-on-the-requested-thread-page","errorCode":null,"errorMessage":"Tieba did not land on the requested thread page","messagePattern":"Tieba did not land on the requested thread page","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"error","filePath":"clis/tieba/read.js","lineNumber":19,"sourceCode":"import { EmptyResultError } from '@jackwener/opencli/errors';\nimport { cli, Strategy } from '@jackwener/opencli/registry';\nimport { buildTiebaReadItems } from './utils.js';\nfunction getThreadUrl(kwargs) {\n    const threadId = String(kwargs.id || '');\n    const pageNumber = Math.max(1, Number(kwargs.page || 1));\n    return `https://tieba.baidu.com/p/${encodeURIComponent(threadId)}?pn=${pageNumber}`;\n}\n/**\n * Ensure the browser actually landed on the requested thread page before we trust the DOM.\n */\nfunction assertTiebaReadTargetPage(raw, kwargs) {\n    const expectedThreadId = String(kwargs.id || '').trim();\n    const expectedPageNumber = Math.max(1, Number(kwargs.page || 1));\n    const pathname = String(raw.pageMeta?.pathname || '').trim();\n    const actualThreadId = pathname.match(/^\\/p\\/(\\d+)/)?.[1] || '';\n    const actualPn = String(raw.pageMeta?.pn || '').trim();\n    if (!actualThreadId || actualThreadId !== expectedThreadId) {\n        throw new EmptyResultError('tieba read', 'Tieba did not land on the requested thread page');\n    }\n    if (expectedPageNumber > 1 && actualPn !== String(expectedPageNumber)) {\n        throw new EmptyResultError('tieba read', 'Tieba did not land on the requested page');\n    }\n}\nfunction buildExtractReadEvaluate() {\n    return `\n    (async () => {\n      const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n      const waitFor = async (predicate, timeoutMs = 4000) => {\n        const start = Date.now();\n        while (Date.now() - start < timeoutMs) {\n          if (predicate()) return true;\n          await wait(100);\n        }\n        return false;\n      };\n      const normalizeText = (value) => (value || '').replace(/\\\\s+/g, ' ').trim();","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tieba/read.js#L1-L37","documentation":"`tieba read` navigates to a thread page (`/p/<id>`) and then asserts, inside `assertTiebaReadTargetPage`, that the browser actually landed on the thread matching `kwargs.id`. This EmptyResultError is thrown when the final URL's pathname does not contain the expected thread id (or the pathname is not a thread page at all). The library treats a wrong-destination navigation as an empty result rather than returning data from the wrong thread, which would silently produce incorrect content.","triggerScenarios":"Calling `tieba read --id <threadId>` when the browser is redirected to a different URL: the thread id in the URL does not match `--id`, the pathname is not `/p/<digits>` (e.g. redirected to a login/verify/captcha page or the tieba home), or `raw.pageMeta.pathname` is empty because page metadata extraction failed.","commonSituations":"Baidu Tieba redirects deleted, private, or banned threads to an interstitial or the forum list; anti-bot verification pages replace the thread URL; passing a wrong/typo'd thread id; the page loaded inside an iframe or SPA state where pageMeta was not captured.","solutions":["Verify the thread id passed via --id (or kwargs.id) is a valid numeric Tieba thread id and still exists (open https://tieba.baidu.com/p/<id> manually).","Re-run the command; transient anti-bot/captcha redirects usually clear on retry, ideally with a persisted logged-in browser profile.","Check whether the page redirected (log raw.pageMeta.pathname) to identify a captcha/login wall, and complete login/verification in the browser session first.","If pageMeta is consistently empty, update the library — Tieba likely changed its page structure."],"exampleFix":"// before\nawait cli.read({ id: '12345', page: 2 }); // thread deleted -> redirected -> EmptyResultError\n// after\n// verify the thread exists first, or handle the redirect\ncurl -sI https://tieba.baidu.com/p/12345 | head -n1 // confirm 200 before calling","handlingStrategy":"validation","validationCode":"// pre-validate before calling tieba read\nif (!/^\\d+$/.test(String(threadId))) {\n  throw new Error('tieba thread id must be numeric');\n}","typeGuard":"function isValidTiebaThreadId(id) {\n  return typeof id === 'string' && /^\\d+$/.test(id);\n}","tryCatchPattern":"import { EmptyResultError } from '@jackwener/opencli/errors';\ntry {\n  return await cli.read({ id: threadId, page });\n} catch (e) {\n  if (e instanceof EmptyResultError) {\n    // wrong-destination navigation: check redirect/captcha, retry once\n    return retryWithBackoff(() => cli.read({ id: threadId, page }), 1);\n  }\n  throw e;\n}","preventionTips":["Validate thread ids are numeric before calling.","Persist a logged-in browser profile to reduce anti-bot redirects.","Log raw.pageMeta.pathname on failure to diagnose redirect targets.","Retry transient failures once with backoff before surfacing to users."],"tags":["tieba","scraping","wrong-page","redirect"],"backgroundTag":"page-redirect-detection","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}