{"record":{"id":"c90e5a979ce8a8f0","repo":"heygen-com/hyperframes","slug":"ref-refinput-has-no-node-id","errorCode":null,"errorMessage":"ref \"${refInput}\" has no node id","messagePattern":"ref \"(.+?)\" has no node id","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/figma/component.ts","lineNumber":58,"sourceCode":"   * \"Platform=Desktop\", which would slug-collide across imports */\n  name?: string;\n}\n\nexport interface ComponentImportResult {\n  name: string;\n  htmlPath: string;\n  unresolved: BindingSite[];\n  rasterized: RasterizeRequest[];\n  /** node ids figma refused to render as svg AND png — placeholders shipped without src */\n  failedRasterize: string[];\n}\n\nexport async function runComponentImport(\n  refInput: string,\n  deps: ComponentImportDeps,\n): Promise<ComponentImportResult> {\n  const ref = parseFigmaRef(refInput);\n  if (!ref.nodeId) throw new Error(`ref \"${refInput}\" has no node id`);\n\n  const tree = await deps.client.nodeTree(ref);\n  const bindings = resolveBindings(tree, readBindings(deps.projectDir));\n  const mapped = nodeToHtml(tree, bindings, { rootName: deps.name });\n\n  const name = slugify(deps.name ?? tree.name);\n  const componentDir = join(deps.projectDir, \"compositions\", \"components\", name);\n  if (existsSync(componentDir))\n    console.warn(\n      `component dir compositions/components/${name} already exists — overwriting (rename the figma frame for a separate import)`,\n    );\n  mkdirSync(componentDir, { recursive: true });\n\n  const { html, frozenAssets, failedRasterize } = await rasterizeFallback(\n    mapped,\n    ref.fileKey,\n    componentDir,\n    deps,","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/figma/component.ts#L40-L76","documentation":"Thrown by runComponentImport() in the component command. It calls parseFigmaRef(refInput) and requires a nodeId, but unlike asset.ts's requireNodeRef it gives no remediation hint in the message. The parsing rules are identical: a bare fileKey or a URL without a non-empty ?node-id yields no nodeId.","triggerScenarios":"`figma component <fileKey>` (bare key); `figma component https://www.figma.com/design/ABC/Name` (no node-id query); `figma component ABC:` (empty node segment).","commonSituations":"Pasting the file URL from the browser address bar rather than a frame's share link; assuming component import accepts a whole file like tokens import does.","solutions":["Copy the link from the specific frame in figma so it carries ?node-id=","Pass fileKey:nodeId, e.g. aBcDeF:1:2","Confirm the node id exists in the current file version"],"exampleFix":"// before\nhyperframes figma component aBcDeF\n// after\nhyperframes figma component aBcDeF:1:2","handlingStrategy":"type-guard","validationCode":"import { parseFigmaRef } from '@hyperframes/core/figma';\nconst ref = parseFigmaRef(refInput);\nif (!ref.nodeId) {\n  throw new Error(`component import needs a node id; use fileKey:nodeId or a ?node-id= URL`);\n}","typeGuard":"import { parseFigmaRef } from '@hyperframes/core/figma';\nfunction refHasNodeId(refInput: string): boolean {\n  try { return Boolean(parseFigmaRef(refInput).nodeId); }\n  catch { return false; }\n}","tryCatchPattern":null,"preventionTips":["Copy the link from the specific frame, not the file address bar","Validate with parseFigmaRef before calling runComponentImport","Keep a helper that normalizes node-id dashes to colons"],"tags":["figma","validation","component","node-id","parse-figma-ref"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}