{"record":{"id":"0e5f0be725ed6ff6","repo":"jackwener/OpenCLI","slug":"could-not-resolve-post-id-from-the-component-page","errorCode":null,"errorMessage":"Could not resolve post.id from the component page: ${normalized.url}","messagePattern":"Could not resolve post\\.id from the component page: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/uiverse/_shared.js","lineNumber":99,"sourceCode":"  const normalized = parseComponentInput(input);\n  await page.goto(normalized.url);\n\n  const raw = await page.evaluate(`(async () => {\n    const key = ${JSON.stringify(ROUTE_DATA_KEY)};\n    const loaderData = window.__remixContext?.state?.loaderData || {};\n    const routeData = loaderData[key];\n    return JSON.stringify({ routeData: routeData || null, keys: Object.keys(loaderData) });\n  })()`);\n\n  const parsed = JSON.parse(raw);\n  let routeData = parsed?.routeData;\n  if (!routeData?.post?.id) {\n    const routeUrl = `${normalized.url}?_data=${encodeURIComponent(ROUTE_DATA_KEY)}`;\n    routeData = await fetchJsonInBrowser(page, routeUrl);\n  }\n\n  if (!routeData?.post?.id) {\n    throw new Error(`Could not resolve post.id from the component page: ${normalized.url}`);\n  }\n\n  return {\n    ...normalized,\n    post: routeData.post,\n    routeData,\n  };\n}\n\nexport async function getRawCode(page, postId) {\n  const codeUrl = `${UIVERSE_BASE_URL}/resource/post/code/${postId}?v=1&_data=${encodeURIComponent(CODE_DATA_KEY)}`;\n  const payload = await fetchJsonInBrowser(page, codeUrl);\n  if (typeof payload?.html !== 'string' || typeof payload?.css !== 'string') {\n    throw new Error(`Unexpected code payload shape: ${codeUrl}`);\n  }\n  return payload;\n}\n","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/uiverse/_shared.js#L81-L117","documentation":"Thrown by getPostDetails when it cannot obtain routeData containing post.id, either from the Remix context embedded in the page (window.__remixContext) or from the ?_data= fallback request. Without post.id the tool cannot fetch the component's raw code, so it aborts.","triggerScenarios":"The component page structure changed so __remixContext.state.loaderData no longer carries 'routes/$username.$friendlyId' with post.id; the ?_data= fallback returns data without post.id (route key renamed after a site update); page.goto failed to hydrate the Remix app before evaluate ran; the URL points to a page that is not a component page.","commonSituations":"Uiverse deploys a framework/router upgrade renaming loader routes; slow page load/hydration so context is missing when evaluated; scraping a profile or element page instead of an individual component page; SSR disabled/changed.","solutions":["Confirm the URL is an individual component page (uiverse.io/<author>/<slug>) that renders a preview","Wait for hydration before evaluating: wait for a known selector or networkidle after page.goto, then retry getPostDetails","Inspect window.__remixContext keys in the live page and update ROUTE_DATA_KEY if the route name changed","Check uiverse.io for API/site changes; update the loader-data extraction logic in clis/uiverse/_shared.js accordingly"],"exampleFix":"// before\nawait page.goto(normalized.url);\nconst details = await getPostDetails(page, input); // context not hydrated yet\n// after\nawait page.goto(normalized.url, { waitUntil: 'networkidle' });\nawait page.waitForSelector('[class*=\"wrapper\"], main', { timeout: 15000 });\nconst details = await getPostDetails(page, input);","handlingStrategy":"retry","validationCode":"await page.goto(url, { waitUntil: 'networkidle' });\nconst hasContext = await page.evaluate(() =>\n  Boolean(window.__remixContext?.state?.loaderData?.['routes/$username.$friendlyId']?.post?.id)\n);\nif (!hasContext) await page.waitForTimeout(2000); // let hydration finish before getPostDetails","typeGuard":"const hasPostId = (routeData) => typeof routeData?.post?.id === 'string' || typeof routeData?.post?.id === 'number';","tryCatchPattern":"try {\n  const details = await getPostDetails(page, input);\n} catch (e) {\n  if (e.message.startsWith('Could not resolve post.id')) {\n    await page.reload({ waitUntil: 'networkidle' }); // retry once after full load\n    return getPostDetails(page, input);\n  }\n  throw e;\n}","preventionTips":["Use waitUntil:'networkidle' and settle delays before extracting Remix context","Confirm you are on a component page (author/slug), not a profile/category page","When uiverse.io ships a router upgrade, update ROUTE_DATA_KEY to the new route name","Detect this error in bulk jobs and fall back to per-page inspection instead of failing the whole run"],"tags":["scraping","site-change","dom-extraction"],"backgroundTag":"selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}