{"record":{"id":"c65d614f4bc9716b","repo":"jackwener/OpenCLI","slug":"could-not-locate-a-uiverse-preview-element-candid","errorCode":null,"errorMessage":"Could not locate a Uiverse preview element. Candidate data: ${JSON.stringify(result)}","messagePattern":"Could not locate a Uiverse preview element\\. Candidate data: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/uiverse/_shared.js","lineNumber":411,"sourceCode":"      const tagNodes = queryAcrossRoots(tagName, 200);\n      for (const node of tagNodes.slice(0, 200)) {\n        collect(node, 'tag:' + tagName);\n      }\n    }\n\n    candidates.sort((left, right) => {\n      if (right.score !== left.score) return right.score - left.score;\n      if (left.rect.y !== right.rect.y) return left.rect.y - right.rect.y;\n      if (left.rect.x !== right.rect.x) return left.rect.x - right.rect.x;\n      return (left.rect.width * left.rect.height) - (right.rect.width * right.rect.height);\n    });\n\n    return JSON.stringify({ signature: sig, best: candidates[0] || null, candidates: candidates.slice(0, 5) });\n  })()`);\n\n  const result = JSON.parse(raw);\n  if (!result?.best?.rect?.width || !result?.best?.rect?.height) {\n    throw new Error(`Could not locate a Uiverse preview element. Candidate data: ${JSON.stringify(result)}`);\n  }\n  return result;\n}\n\nexport function getDefaultOutputPath({ username, slug, suffix, extension }) {\n  const safeUsername = trimPathSegment(username).replace(/[^a-zA-Z0-9-_]/g, '-');\n  const safeSlug = trimPathSegment(slug).replace(/[^a-zA-Z0-9-_]/g, '-');\n  return path.join(os.tmpdir(), `opencli-uiverse-${safeUsername}-${safeSlug}-${suffix}.${extension}`);\n}\n\nexport async function saveBase64File(base64, outputPath) {\n  const resolved = path.resolve(outputPath);\n  await fs.mkdir(path.dirname(resolved), { recursive: true });\n  await fs.writeFile(resolved, Buffer.from(base64, 'base64'));\n  return resolved;\n}\n","sourceCodeStart":393,"sourceCodeEnd":428,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/uiverse/_shared.js#L393-L428","documentation":"Thrown by locatePreviewElement when the in-page scoring pass finds no visible candidate element with a non-zero-size rect matching the component's HTML root signature (tag/id/classes, with fallback tags like label/button/a/div). The error embeds the top candidate data to help debug why nothing matched.","triggerScenarios":"The page has no visible element matching the component's root signature and no usable fallback candidates (everything hidden, zero-size, or inside a dialog); getRawCode returned html whose root signature (e.g. an exotic custom element tag) matches nothing on the rendered page; the component renders inside an iframe the search doesn't traverse; the page didn't finish rendering when evaluated.","commonSituations":"Preview renders in a shadow root/iframe not reachable by the traversal; CSS keeps the root at opacity 0 or display none until user interaction; components whose root is a custom element (e.g. <my-widget>) not covered by fallback tags; race where screenshot/preview is taken before layout completes.","solutions":["Log the Candidate data in the error: if best is null nothing matched, if rects are 0 it is hidden — adjust visibility waits accordingly","Wait for rendering: page.waitForSelector or waitForTimeout/networkidle before calling locatePreviewElement","If the root tag is a custom element, extend getPreviewFallbackTags in clis/uiverse/_shared.js to include it or its host container","Check for iframes: switch to the component frame (page.frames) before locating the preview"],"exampleFix":"// before\nconst preview = await locatePreviewElement(page, html); // page still hydrating\n// after\nawait page.waitForLoadState('networkidle');\nawait page.waitForTimeout(1000); // allow layout/animation\nconst preview = await locatePreviewElement(page, html);","handlingStrategy":"try-catch","validationCode":"await page.goto(componentUrl, { waitUntil: 'networkidle' });\nawait page.waitForTimeout(500); // ensure layout settled\nconst sig = parseHtmlRootSignature(html);\nif (sig.tag && !['div','button','label','a','input'].includes(sig.tag)) {\n  console.warn('Custom-element root may not be locatable:', sig.tag);\n}","typeGuard":"const hasVisibleRect = (r) => r?.rect?.width > 0 && r?.rect?.height > 0;","tryCatchPattern":"try {\n  const preview = await locatePreviewElement(page, html);\n} catch (e) {\n  if (e.message.startsWith('Could not locate a Uiverse preview element')) {\n    await page.waitForTimeout(2000); // late-rendering content\n    return locatePreviewElement(page, html);\n  }\n  throw e;\n}","preventionTips":["Wait for rendering (networkidle + settle delay) before locating the preview","Parse the Candidate data in the error message — it shows why nothing matched (null vs zero-rect)","Handle iframe/shadow-root previews by extending traversal or switching frames","Extend getPreviewFallbackTags for components whose root is an unusual tag"],"tags":["dom-extraction","scraping","layout"],"backgroundTag":"element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}