jackwener/OpenCLI · error · Error

Could not locate a Uiverse preview element. Candidate data:

Error message

Could not locate a Uiverse preview element. Candidate data: ${JSON.stringify(result)}

What it means

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.

Source

Thrown at clis/uiverse/_shared.js:411

      const tagNodes = queryAcrossRoots(tagName, 200);
      for (const node of tagNodes.slice(0, 200)) {
        collect(node, 'tag:' + tagName);
      }
    }

    candidates.sort((left, right) => {
      if (right.score !== left.score) return right.score - left.score;
      if (left.rect.y !== right.rect.y) return left.rect.y - right.rect.y;
      if (left.rect.x !== right.rect.x) return left.rect.x - right.rect.x;
      return (left.rect.width * left.rect.height) - (right.rect.width * right.rect.height);
    });

    return JSON.stringify({ signature: sig, best: candidates[0] || null, candidates: candidates.slice(0, 5) });
  })()`);

  const result = JSON.parse(raw);
  if (!result?.best?.rect?.width || !result?.best?.rect?.height) {
    throw new Error(`Could not locate a Uiverse preview element. Candidate data: ${JSON.stringify(result)}`);
  }
  return result;
}

export function getDefaultOutputPath({ username, slug, suffix, extension }) {
  const safeUsername = trimPathSegment(username).replace(/[^a-zA-Z0-9-_]/g, '-');
  const safeSlug = trimPathSegment(slug).replace(/[^a-zA-Z0-9-_]/g, '-');
  return path.join(os.tmpdir(), `opencli-uiverse-${safeUsername}-${safeSlug}-${suffix}.${extension}`);
}

export async function saveBase64File(base64, outputPath) {
  const resolved = path.resolve(outputPath);
  await fs.mkdir(path.dirname(resolved), { recursive: true });
  await fs.writeFile(resolved, Buffer.from(base64, 'base64'));
  return resolved;
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Log the Candidate data in the error: if best is null nothing matched, if rects are 0 it is hidden — adjust visibility waits accordingly
  2. Wait for rendering: page.waitForSelector or waitForTimeout/networkidle before calling locatePreviewElement
  3. If the root tag is a custom element, extend getPreviewFallbackTags in clis/uiverse/_shared.js to include it or its host container
  4. Check for iframes: switch to the component frame (page.frames) before locating the preview

Example fix

// before
const preview = await locatePreviewElement(page, html); // page still hydrating
// after
await page.waitForLoadState('networkidle');
await page.waitForTimeout(1000); // allow layout/animation
const preview = await locatePreviewElement(page, html);
Defensive patterns

Strategy: try-catch

Validate before calling

await page.goto(componentUrl, { waitUntil: 'networkidle' });
await page.waitForTimeout(500); // ensure layout settled
const sig = parseHtmlRootSignature(html);
if (sig.tag && !['div','button','label','a','input'].includes(sig.tag)) {
  console.warn('Custom-element root may not be locatable:', sig.tag);
}

Type guard

const hasVisibleRect = (r) => r?.rect?.width > 0 && r?.rect?.height > 0;

Try / catch

try {
  const preview = await locatePreviewElement(page, html);
} catch (e) {
  if (e.message.startsWith('Could not locate a Uiverse preview element')) {
    await page.waitForTimeout(2000); // late-rendering content
    return locatePreviewElement(page, html);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/c65d614f4bc9716b. Report an issue: GitHub.