{"record":{"id":"a577e41e9bc7f1e8","repo":"jackwener/OpenCLI","slug":"failed-to-extract-targetlabel-export-code","errorCode":null,"errorMessage":"Failed to extract ${targetLabel} export code.","messagePattern":"Failed to extract (.+?) export code\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/uiverse/_shared.js","lineNumber":253,"sourceCode":"    const dialog = document.querySelector('[role=\"dialog\"]');\n    if (longest && longestLooksComplete) {\n      return JSON.stringify({ ok: true, code: longest, length: longest.length, fallback: true });\n    }\n\n    return JSON.stringify({\n      ok: false,\n      error: dialog\n        ? (targetLabel + ' dialog appeared, but the exported code never reached a stable complete state.')\n        : (targetLabel + ' export dialog did not appear after clicking the export controls.'),\n      dialogFound: Boolean(dialog),\n      dialogText: dialog ? (dialog.innerText || '').slice(0, 200) : null,\n      longestLength: longest.length,\n    });\n  })()`);\n\n  const data = JSON.parse(raw);\n  if (!data?.ok || typeof data.code !== 'string') {\n    throw new Error(data?.error || `Failed to extract ${targetLabel} export code.`);\n  }\n  return data.code;\n}\n\nexport function parseHtmlRootSignature(html) {\n  const source = String(html || '').trim();\n  const match = source.match(/^<([a-zA-Z0-9-]+)([^>]*)>/);\n  if (!match) {\n    return { tag: null, id: null, classes: [] };\n  }\n\n  const [, tag, attrs] = match;\n  const idMatch = attrs.match(/\\sid=[\"']([^\"']+)[\"']/i);\n  const classMatch = attrs.match(/\\sclass=[\"']([^\"']+)[\"']/i);\n  const classes = classMatch ? classMatch[1].split(/\\s+/).filter(Boolean) : [];\n  return {\n    tag: tag.toLowerCase(),\n    id: idMatch ? idMatch[1] : null,","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/uiverse/_shared.js#L235-L271","documentation":"Thrown by extractExportCode when the in-page export automation fails. The in-browser script clicks the Export button and the React/Vue target, polls the export dialog textarea until the code is complete and stable, and returns { ok:false, error } on any failure; the Node side then throws with the browser-reported reason (or this generic fallback message).","triggerScenarios":"No Export button exists on the page (not logged in, or uiverse.io removed/renamed the control); the export dialog never opens after clicking; the dialog opens but the code never reaches a stable 'complete' state within ~8s of polling; the target (React/Vue) menu item never appears; the textarea read returns partial code for 40 consecutive checks.","commonSituations":"Scraping without authentication where Export is disabled; slow page/CPU causing the 200ms x 40 polling window to expire before the dialog renders; uiverse.io UI redesign moving the Export button or dialog markup; components whose exported code never matches the isCompleteExportCode heuristics (missing 'export default'/styled markers or template/style tags).","solutions":["Check the thrown message (data.error) for the specific sub-failure ('Could not find the export controls', 'did not appear', 'never reached a stable complete state') and act on it","Ensure you are logged in inside the browser page so the Export controls render","Increase polling tolerance: raise the 40x200ms loop or initial delays in the page.evaluate script for slow environments","If the UI changed, update the selectors ('button' text 'Export', '[role=\"dialog\"] textarea', target labels) in clis/uiverse/_shared.js to match the new markup"],"exampleFix":"// before\nconst code = await extractExportCode(page, 'react'); // times out on slow page\n// after\ntry {\n  var code = await extractExportCode(page, 'react');\n} catch (e) {\n  await page.waitForTimeout(3000); // let UI settle, retry once\n  var code = await extractExportCode(page, 'react');\n}","handlingStrategy":"try-catch","validationCode":"// Verify export controls exist before attempting extraction:\nconst hasExport = await page.locator('button', { hasText: 'Export' }).count();\nif (!hasExport) throw new Error('Export button not rendered — are you logged in?');","typeGuard":"const isExportResult = (d) => d?.ok === true && typeof d?.code === 'string' && d.code.length > 0;","tryCatchPattern":"try {\n  const code = await extractExportCode(page, target);\n} catch (e) {\n  const msg = e.message;\n  if (msg.includes('Could not find the export controls')) {\n    throw new Error('Not logged in or Export UI changed');\n  }\n  if (msg.includes('never reached a stable complete state')) {\n    await page.waitForTimeout(5000);\n    return extractExportCode(page, target); // retry once for slow renders\n  }\n  throw e;\n}","preventionTips":["Ensure an authenticated session — Export controls may be gated on login","Prefer getRawCode (direct data endpoint) over UI export automation when possible","Allow generous timeouts for slow machines; the in-page poll window is only ~8s","After any uiverse.io UI redesign, re-verify button labels and dialog selectors"],"tags":["dom-extraction","scraping","ui-automation","timeout"],"backgroundTag":"element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}