{"record":{"id":"c9ae3b9d10508566","repo":"nexu-io/open-design","slug":"brand-missing-required-name","errorCode":null,"errorMessage":"brand: missing required `name`","messagePattern":"brand: missing required `name`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/brands/validate.ts","lineNumber":55,"sourceCode":"  return {\n    family: isStr(o.family) && o.family ? o.family : fallbackFamily,\n    fallbacks: strArr(o.fallbacks),\n    weights: Array.isArray(o.weights) ? o.weights.filter((w) => typeof w === 'number') : [400, 700],\n    ...(isStr(o.googleFontsUrl) && o.googleFontsUrl ? { googleFontsUrl: o.googleFontsUrl } : {}),\n    ...(isStr(o.notes) && o.notes ? { notes: o.notes } : {}),\n  };\n}\n\n/**\n * Validate + normalize a brand object. Throws with a precise message on\n * unrecoverable problems (missing name/colors); fills sensible defaults for\n * everything optional so a slightly-sloppy input still renders.\n */\nexport function validateBrand(raw: unknown, sourceUrl: string): Brand {\n  if (!raw || typeof raw !== 'object') throw new Error('brand is not a JSON object');\n  const o = raw as Record<string, unknown>;\n\n  if (!isStr(o.name) || !o.name.trim()) throw new Error('brand: missing required `name`');\n\n  const rawColors = Array.isArray(o.colors) ? o.colors : [];\n  const colors: BrandColor[] = [];\n  for (const c of rawColors) {\n    if (!c || typeof c !== 'object') continue;\n    const co = c as Record<string, unknown>;\n    const role = BRAND_COLOR_ROLES.includes(co.role as BrandColorRole)\n      ? (co.role as BrandColorRole)\n      : null;\n    const hex = isStr(co.hex) && /^#[0-9a-fA-F]{6}$/.test(co.hex) ? co.hex.toLowerCase() : null;\n    if (!role || !hex) continue;\n    colors.push({\n      role,\n      hex,\n      oklch: isStr(co.oklch) ? co.oklch : '',\n      name: isStr(co.name) ? co.name : role,\n      usage: isStr(co.usage) ? co.usage : '',\n    });","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/brands/validate.ts#L37-L73","documentation":"Thrown by validateBrand when the object has no non-empty string `name` field. name is the only hard-required scalar on a Brand — without it, kit pages, deck titles, and meta cannot render. The check is `typeof o.name === 'string' && o.name.trim().length > 0`.","triggerScenarios":"validateBrand receives an object whose `name` is missing, empty, whitespace-only, or not a string (a number, null, array). Common when the extractor emits a brand with a `brandName` or `title` field instead of `name`.","commonSituations":"LLM uses a synonym ('brandName', 'title', 'company') instead of `name`; name field left blank; name field set to a number (e.g. a founding year) by a sloppy extraction; an upstream rename that did not migrate old brand.json.","solutions":["Alias common synonyms to `name` before validateBrand: if (!o.name && o.brandName) o.name = o.brandName;","Improve the extraction prompt to require `name` as a non-empty string.","Re-prompt the agent with this exact error message when extraction omits name.","Add a pre-check that fails fast with a clearer message for the synonym case."],"exampleFix":"// before\nconst o = raw as Record<string, unknown>;\nconst brand = validateBrand(o, sourceUrl);\n// after — normalize synonyms before validation\nif (!o.name) o.name = o.brandName ?? o.title ?? o.company;\nconst brand = validateBrand(o, sourceUrl);","handlingStrategy":"validation","validationCode":"if (!o.name) o.name = o.brandName ?? o.title ?? o.company;\nif (typeof o.name !== 'string' || !o.name.trim()) {\n  throw new Error('brand: missing required `name`');\n}","typeGuard":"const hasBrandName = (o: Record<string, unknown>): boolean =>\n  typeof o.name === 'string' && o.name.trim().length > 0;","tryCatchPattern":null,"preventionTips":["Alias common synonyms (brandName, title, company) onto name before validation.","Prompt the extractor to require a non-empty `name`.","Re-prompt with the exact error message on failure."],"tags":["brand","validation","schema","required-field","llm-output"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}