{"record":{"id":"e6faebf75537c953","repo":"heygen-com/hyperframes","slug":"parsefigmaref-invalid-ref-input","errorCode":null,"errorMessage":"parseFigmaRef: invalid ref \"${input}\"","messagePattern":"parseFigmaRef: invalid ref \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/figma/parseFigmaRef.ts","lineNumber":18,"sourceCode":"import type { FigmaRef } from \"./types\";\n\nconst FILE_KEY_RE = /\\/(?:design|file|proto)\\/([A-Za-z0-9]+)/;\n\nfunction normalizeNodeId(raw: string): string {\n  return raw.replaceAll(\"-\", \":\");\n}\n\nexport function parseFigmaRef(input: string): FigmaRef {\n  const trimmed = input.trim();\n  if (trimmed.length === 0) throw new Error(\"parseFigmaRef: empty input\");\n\n  if (!trimmed.includes(\"/\")) {\n    const colon = trimmed.indexOf(\":\");\n    if (colon === -1) return { fileKey: trimmed };\n    const fileKey = trimmed.slice(0, colon);\n    const node = trimmed.slice(colon + 1);\n    if (fileKey.length === 0) throw new Error(`parseFigmaRef: invalid ref \"${input}\"`);\n    return node.length > 0 ? { fileKey, nodeId: normalizeNodeId(node) } : { fileKey };\n  }\n\n  const keyMatch = trimmed.match(FILE_KEY_RE);\n  const fileKey = keyMatch?.[1];\n  if (fileKey === undefined) throw new Error(`parseFigmaRef: no fileKey in \"${input}\"`);\n\n  const q = trimmed.indexOf(\"?\");\n  if (q !== -1) {\n    const raw = new URLSearchParams(trimmed.slice(q + 1)).get(\"node-id\");\n    if (raw !== null && raw.length > 0) return { fileKey, nodeId: normalizeNodeId(raw) };\n  }\n  return { fileKey };\n}\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/core/src/figma/parseFigmaRef.ts#L1-L33","documentation":"Thrown by parseFigmaRef when the input has no '/' but does have a colon, AND the substring before the colon (the would-be fileKey) is empty. This is the ':nodeId' / '  :1234' shape — a ref that names a node but no file. Because fileKey is the one field that must always be present on a FigmaRef, the parser rejects this combination outright rather than returning { fileKey: '' }. A colon-form with a non-empty fileKey (e.g. 'abc:12:34') is accepted and the node part normalised.","triggerScenarios":"Input like ':12:34' (fileKey missing, node present); input like '  :node' after trimming; a ref string that lost its fileKey prefix during string manipulation; a user typing only the nodeId thinking that was the whole ref.","commonSituations":"User pastes only the node-id portion copied from the figma URL's query string; a script concatenates ':' + nodeId but leaves the fileKey side blank due to an upstream bug; refactoring that drops the fileKey variable.","solutions":["Provide the fileKey before the colon: 'aBcDeF1234:12:34'.","Prefer the full figma URL form (parseFigmaRef handles the URL parsing) to avoid manual colon-form mistakes.","If building the ref programmatically, assert fileKey is non-empty before concatenating."],"exampleFix":"// before — fileKey side empty\nconst ref = parseFigmaRef(`:${nodeId}`);\n\n// after — fileKey included\nconst ref = parseFigmaRef(`${fileKey}:${nodeId}`);","handlingStrategy":"validation","validationCode":"export function buildColonRef(fileKey: string, nodeId: string): string {\n  if (!fileKey) throw new Error('fileKey is required before the colon');\n  return `${fileKey}:${nodeId}`;\n}\nparseFigmaRef(buildColonRef(fileKey, nodeId));","typeGuard":null,"tryCatchPattern":"try {\n  const ref = parseFigmaRef(input);\n} catch (err) {\n  if (err instanceof Error && /invalid ref/.test(err.message)) {\n    // prompt user for the fileKey portion\n  } else throw err;\n}","preventionTips":["When concatenating 'fileKey:nodeId', assert fileKey is non-empty first.","Prefer passing the full figma URL through parseFigmaRef rather than building colon-form by hand.","In UI inputs, validate that a fileKey was entered before accepting the ref."],"tags":["figma","parsing","validation","input"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}