{"record":{"id":"9424dcd59a9a31b3","repo":"jackwener/OpenCLI","slug":"tieba-did-not-land-on-the-requested-page","errorCode":null,"errorMessage":"Tieba did not land on the requested page","messagePattern":"Tieba did not land on the requested page","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"error","filePath":"clis/tieba/read.js","lineNumber":22,"sourceCode":"function 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();\n      const getVueProps = (element) => {\n        const vue = element && element.__vue__ ? element.__vue__ : null;\n        return vue ? (vue._props || vue.$props || {}) : {};","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tieba/read.js#L4-L40","documentation":"When `tieba read` is asked for a page beyond the first (`kwargs.page > 1`), `assertTiebaReadTargetPage` compares the actual `pn` query parameter captured in `raw.pageMeta.pn` with the requested page number and throws this EmptyResultError on mismatch. This guards against returning page-1 content when the caller asked for a later page — a common failure because Tieba pagination via URL often snaps back to page 1. The library refuses to return mis-paginated data.","triggerScenarios":"Calling `tieba read --id <threadId> --page N` (N>1) when the landed page's `pn` query param is not N: the thread has fewer pages than requested (Tieba clamps/redirects to last or first page), the pagination click/goto did not take effect, or pageMeta.pn was not extracted.","commonSituations":"Requesting a page number beyond the thread's total page count; deleted/filtered posts shrinking the page count between runs; SPA pagination that doesn't update the URL; scraping automation racing ahead of navigation completion.","solutions":["Check the thread actually has the requested page count; reduce --page if the thread is shorter (Tieba silently falls back to an earlier page).","Re-run — a transient navigation race may land on the wrong page; add a small delay or retry.","Fetch page 1 first and inspect its total-page metadata to determine a valid max page before requesting higher pages.","If it persists on valid pages, the pageMeta extraction (raw.pageMeta.pn) is likely broken by a Tieba DOM/URL change — update the library."],"exampleFix":"// before\nawait cli.read({ id: '12345', page: 99 }); // thread only has 3 pages -> clamped -> EmptyResultError\n// after\nconst first = await cli.read({ id: '12345', page: 1 });\nconst lastPage = first.pageMeta?.totalPage ?? 1;\nawait cli.read({ id: '12345', page: Math.min(3, lastPage) });","handlingStrategy":"validation","validationCode":"// confirm requested page is plausible before calling\nif (!Number.isInteger(page) || page < 1) {\n  throw new Error('page must be a positive integer');\n}","typeGuard":"function isValidTiebaPage(page) {\n  return Number.isInteger(page) && page >= 1;\n}","tryCatchPattern":"try {\n  return await cli.read({ id: threadId, page });\n} catch (e) {\n  if (e instanceof EmptyResultError && page > 1) {\n    // thread may be shorter than requested: fall back to page 1\n    return cli.read({ id: threadId, page: 1 });\n  }\n  throw e;\n}","preventionTips":["Discover total page count from page-1 metadata before requesting higher pages.","Clamp requested page to the thread's actual last page.","Treat page-1 fallback as the standard recovery for out-of-range pages.","Cache thread page counts to avoid repeated out-of-range requests."],"tags":["tieba","scraping","pagination"],"backgroundTag":"pagination-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}