{"record":{"id":"f5229d2c223a4758","repo":"nexu-io/open-design","slug":"brand-json-not-found-for-brand-id","errorCode":null,"errorMessage":"brand.json not found for brand \"${id}\"","messagePattern":"brand\\.json not found for brand \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/brands/system.ts","lineNumber":130,"sourceCode":"  process.exit(1);\n}\n\nconst here = path.dirname(fileURLToPath(import.meta.url));\nconst source = path.resolve(here, '..', 'variables.css');\nconst destination = path.resolve(process.cwd(), target);\nfs.mkdirSync(path.dirname(destination), { recursive: true });\nfs.copyFileSync(source, destination);\nconsole.log(\\`Copied design tokens to \\${destination}\\`);\n`;\n}\n\nexport async function rebuildSystem(\n  brandsRoot: string,\n  id: string,\n  seedOverrides?: Partial<SeedToken>,\n): Promise<{ themes: string[]; files: string[] }> {\n  const brand = readBrand(brandsRoot, id) as Brand | null;\n  if (!brand) throw new Error(`brand.json not found for brand \"${id}\"`);\n\n  if (seedOverrides !== undefined) {\n    const merged = sanitizeSeedOverrides({ ...brand.seed, ...seedOverrides });\n    if (merged) brand.seed = merged;\n    else delete brand.seed;\n    writeBrand(brandsRoot, id, brand);\n  }\n\n  const overrides = sanitizeSeedOverrides(brand.seed);\n  const fontFiles = readFontManifest(brandRoot(brandsRoot, id));\n  let system = buildBrandSystem(brand, { fontFiles });\n  if (overrides) {\n    system = reassembleWithSeed(system, brand, { ...system.seed, ...overrides }, fontFiles);\n  }\n\n  // Layout-validation guard: the deck lays content on fixed-size 16:9 slides,\n  // so a regressed template can clip / truncate / overflow brand copy. Block\n  // the rebuild before anything is written when the no-clip invariants fail.","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/brands/system.ts#L112-L148","documentation":"Thrown by rebuildSystem when readBrand returns null — the brand dir has no readable brand.json. Distinct from an invalid id: the id passed the regex, but the canonical Brand file is missing or unreadable. rebuildSystem cannot proceed because the entire system is derived from the Brand object.","triggerScenarios":"rebuildSystem(brandsRoot, id) where the brand dir exists but brand.json was never written (extraction started but did not finish), was deleted, is corrupted JSON (readBrand swallows parse errors and returns null), or the id points at a dir that pre-dates the brand.json schema.","commonSituations":"Rebuild invoked on a still-extracting brand; rebuild after a partial/crashed extraction; brand.json deleted by hand; an old fixture dir lacking brand.json; race between delete and rebuild.","solutions":["Wait for extraction to reach the terminal state (check BrandMeta.extractionTerminalRunId / state) before rebuild.","If the brand was deleted, surface a 404 to the caller and remove it from any cached list.","If brand.json is corrupted, re-run extraction rather than reconstructing the file by hand.","Guard rebuild with readBrand(brandsRoot, id) !== null and a meta state check."],"exampleFix":"// before\nawait rebuildSystem(brandsRoot, id); // throws if brand.json missing\n// after\nconst brand = readBrand(brandsRoot, id);\nif (!brand) throw new HttpError(404, `brand not extracted yet: ${id}`);\nif (!isExtractionTerminal(readMeta(brandsRoot, id))) {\n  throw new HttpError(409, 'extraction still running');\n}\nawait rebuildSystem(brandsRoot, id);","handlingStrategy":"validation","validationCode":"import { readBrand, readMeta } from './store.js';\nconst brand = readBrand(brandsRoot, id);\nif (!brand) throw new Error(`brand.json missing for ${id}`);\nconst meta = readMeta(brandsRoot, id);\nif (!isExtractionTerminal(meta)) throw new Error('extraction not terminal');","typeGuard":null,"tryCatchPattern":"try { await rebuildSystem(brandsRoot, id); }\ncatch (e) {\n  if (String(e.message).startsWith('brand.json not found for brand')) {\n    return res.status(404).json({ error: e.message });\n  }\n  throw e;\n}","preventionTips":["Wait for extraction to reach the terminal state before rebuild.","Surface 404 for a missing brand.json rather than letting rebuildSystem throw.","Re-extract rather than hand-repairing corrupted brand.json."],"tags":["brand","design-system","lifecycle","filesystem","state"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}