{"record":{"id":"765f01355c1e740d","repo":"jackwener/OpenCLI","slug":"actionlabel-failed-result-error-invalid","errorCode":null,"errorMessage":"${actionLabel} failed: ${result?.error || 'invalid browser response'}","messagePattern":"(.+?) failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/hupu/utils.js","lineNumber":97,"sourceCode":"        };\n      }\n\n      try {\n        const text = document.getElementById('__NEXT_DATA__')?.textContent || '';\n        return {\n          ok: true,\n          data: JSON.parse(text)\n        };\n      } catch (error) {\n        return {\n          ok: false,\n          error: error instanceof Error ? error.message : String(error)\n        };\n      }\n    })()\n  `);\n    if (!result || typeof result !== 'object' || !result.ok) {\n        throw new CommandExecutionError(`${actionLabel} failed: ${result?.error || 'invalid browser response'}`);\n    }\n    return result.data;\n}\nexport async function readHupuSearchData(page, url, actionLabel) {\n    await page.goto(url);\n    const result = await page.evaluate(`\n    (async () => {\n      const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));\n      const waitFor = async (predicate, timeoutMs = 5000) => {\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\n      const extractFromScript = () => {","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/hupu/utils.js#L79-L115","documentation":"readHupuNextData waits up to ~5s for the page's `__NEXT_DATA__` script tag (optionally matching an expected tid) and parses it. If page.evaluate returns a falsy/non-object value, or `{ok:false, error}` (timeout, tid mismatch, or JSON.parse failure inside the browser), the helper throws CommandExecutionError with the browser-reported error, or the fallback 'invalid browser response' when result itself is unusable. It means Hupu's Next.js page data never became available or was not parseable.","triggerScenarios":"Any hupu read command backed by readHupuNextData when: the thread page never renders __NEXT_DATA__ within timeoutMs (default 5000), the rendered thread's tid differs from options.expectedTid (redirect/wrong tid), __NEXT_DATA__ is malformed JSON, or page.evaluate returns undefined/null so result?.error is undefined.","commonSituations":"Deleted or wrong thread tid causing a redirect to a different thread, Hupu serving a login/verification wall instead of the data page, slow network exceeding the 5s timeout, or Hupu changing its page framework so __NEXT_DATA__ no longer exists.","solutions":["Read the inner message (tid mismatch includes expected/actual tid and href) to see whether it was a timeout, tid mismatch, or missing data.","Verify the tid/URL is a valid, existing thread and that the page loads in a normal browser.","Increase options.timeoutMs if the network is slow; re-run the command.","Log in to Hupu (or refresh cookies) if the site is serving an anti-bot or login page instead of thread data.","If __NEXT_DATA__ is gone entirely, the site changed rendering — the CLI needs a parser update."],"exampleFix":"// before\nconst data = await readHupuNextData(page, url, 'Read thread', { expectedTid: tid });\n// after — give slow pages more time and validate tid first\nif (!/^\\d{9}$/.test(String(tid))) throw new Error(`invalid tid: ${tid}`);\nconst data = await readHupuNextData(page, url, 'Read thread', { expectedTid: String(tid), timeoutMs: 15000 });","handlingStrategy":"try-catch","validationCode":"// pre-check the target thread before extraction\nconst res = await page.goto(threadUrl);\nif (!res || !res.ok()) throw new Error(`thread page unreachable: ${threadUrl}`);\nconst hasNextData = await page.evaluate(() => Boolean(document.getElementById('__NEXT_DATA__')));\nif (!hasNextData) console.warn('__NEXT_DATA__ not yet present; may need login or longer wait');","typeGuard":"function isNextDataResult(r) {\n  return typeof r === 'object' && r !== null && 'ok' in r && (r.ok !== true || 'data' in r);\n}","tryCatchPattern":"try {\n  const data = await readHupuNextData(page, url, 'Read thread', { expectedTid, timeoutMs: 15000 });\n} catch (err) {\n  if (/tid不匹配/.test(err.message)) {\n    const m = err.message.match(/expected=([^,]+), actual=([^,]+)/);\n    console.error(`Redirected thread: wanted ${m?.[1]}, got ${m?.[2]}`);\n  } else if (/无法找到帖子数据/.test(err.message)) {\n    await refreshSession(); // likely a login/anti-bot wall\n  }\n  throw err;\n}","preventionTips":["Pass a higher timeoutMs on slow networks instead of the 5s default.","Always pass expectedTid so redirects/mismatches are detected with a clear message.","Verify the thread exists in a normal browser before assuming a CLI bug.","Keep the session logged in — data pages behind login walls lack __NEXT_DATA__.","Watch for Hupu frontend changes: if __NEXT_DATA__ disappears site-wide, extraction logic needs updating."],"tags":["hupu","scraping","timeout","dom-parsing"],"backgroundTag":"page-data-extraction-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}