{"record":{"id":"9b341849d3674a46","repo":"nexu-io/open-design","slug":"invalid-brand-id-id-9b3418","errorCode":null,"errorMessage":"invalid brand id: ${id}","messagePattern":"invalid brand id: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/brands/system.ts","lineNumber":40,"sourceCode":"  type SeedToken,\n  type ThemeAlgorithm,\n} from './engine/index.js';\nimport type { AssetKind, Brand } from './schema.js';\n\nexport const BRAND_ARTIFACT_KINDS: AssetKind[] = [\n  'landing',\n  'deck',\n  'poster',\n  'email',\n  'newsletter',\n  'form',\n];\n\nconst THEME_ALGORITHMS: ThemeAlgorithm[] = ['default', 'dark', 'compact'];\n\nfunction brandRoot(brandsRoot: string, id: string): string {\n  const dir = resolveBrandFile(brandsRoot, id, []);\n  if (!dir) throw new Error(`invalid brand id: ${id}`);\n  return dir;\n}\n\nexport function brandSystemDir(brandsRoot: string, id: string): string {\n  return path.join(brandRoot(brandsRoot, id), 'system');\n}\n\nfunction reassembleWithSeed(\n  base: BrandSystem,\n  brand: Brand,\n  seed: SeedToken,\n  fontFiles: FontFile[],\n): BrandSystem {\n  const themes: Record<ThemeAlgorithm, DesignTokens> = {\n    default: deriveTokens(seed, 'default'),\n    dark: deriveTokens(seed, 'dark'),\n    compact: deriveTokens(seed, 'compact'),\n  };","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/brands/system.ts#L22-L58","documentation":"Thrown by the private brandRoot helper in system.ts when resolveBrandFile(brandsRoot, id, []) returns null. brandRoot backs brandSystemDir and readFontManifest inside rebuildSystem, so any caller of rebuildSystem with an invalid id ultimately hits this. Same regex + traversal guard as the store.","triggerScenarios":"rebuildSystem(brandsRoot, id) invoked with an id that fails isValidBrandId. Because rebuildSystem first calls readBrand (which returns null for the same invalid id), error [51] usually fires first — but if readBrand is bypassed or the id is valid-yet-missing, brandRoot throws here instead.","commonSituations":"Rebuild route that accepts the id from the request path; tests that call rebuildSystem directly with a fabricated id; a stale id cached after the brand was deleted; a refactor that called brandSystemDir before readBrand.","solutions":["Validate the id with isValidBrandId and confirm readBrand(brandsRoot, id) !== null before rebuildSystem.","Source rebuild ids from listBrandIds output only.","In the rebuild route, return 404 for a missing brand rather than letting brandRoot throw.","Order checks in rebuildSystem consumers: exists -> rebuild, so brandRoot is never reached for missing ids."],"exampleFix":"// before\nawait rebuildSystem(brandsRoot, id);\n// after\nimport { isValidBrandId, readBrand } from './store.js';\nif (!isValidBrandId(id) || !readBrand(brandsRoot, id)) {\n  throw new HttpError(404, `brand not found: ${id}`);\n}\nawait rebuildSystem(brandsRoot, id);","handlingStrategy":"validation","validationCode":"import { isValidBrandId, readBrand } from './store.js';\nif (!isValidBrandId(id) || !readBrand(brandsRoot, id)) {\n  throw new Error(`brand not found: ${id}`);\n}","typeGuard":"import { isValidBrandId } from './store.js';\nconst isBrandId = (id: unknown): id is string =>\n  typeof id === 'string' && isValidBrandId(id);","tryCatchPattern":null,"preventionTips":["Validate id and existence before rebuildSystem.","Source rebuild ids from listBrandIds output.","Order checks: exists -> rebuild, so brandRoot is never reached for missing ids."],"tags":["brand","id-validation","design-system","filesystem"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}