{"record":{"id":"88b41c4dd85c57fa","repo":"nexu-io/open-design","slug":"brand-json-is-not-valid-json","errorCode":null,"errorMessage":"brand.json is not valid JSON.","messagePattern":"brand\\.json is not valid JSON\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/brands/index.ts","lineNumber":1347,"sourceCode":"  opts: FinalizeBrandOptions,\n): Promise<BrandFinalizeResponse> {\n  const { id, brandsRoot, projectsRoot } = opts;\n  const meta = readMeta(brandsRoot, id);\n  if (!meta) throw new Error(`brand not found: ${id}`);\n  const projectId = opts.projectId ?? meta.projectId ?? brandProjectId(id);\n\n  const brandJsonRaw = await readProjectTextOrNull(projectsRoot, projectId, 'brand.json');\n  if (brandJsonRaw === null) {\n    throw new Error(\n      'brand.json not found in the extraction project — the agent has not written the design system yet.',\n    );\n  }\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(brandJsonRaw);\n  } catch {\n    const block = extractJsonBlock(brandJsonRaw);\n    if (block === null) throw new Error('brand.json is not valid JSON.');\n    parsed = block;\n  }\n  let brand: Brand;\n  try {\n    brand = validateBrand(parsed, meta.sourceUrl);\n  } catch (err) {\n    throw new Error(`brand.json failed validation: ${errorMessage(err)}`);\n  }\n\n  // Pull the agent's downloaded assets into the brand workspace so the\n  // deterministic builder and the design system see them.\n  copyProjectDirToBrand(projectsRoot, projectId, brandsRoot, id, 'logos');\n  copyProjectDirToBrand(projectsRoot, projectId, brandsRoot, id, 'fonts');\n  copyProjectDirToBrand(projectsRoot, projectId, brandsRoot, id, 'imagery');\n\n  const guideMd =\n    (await readProjectTextOrNull(projectsRoot, projectId, 'BRAND.md')) ?? brandGuideMd(brand);\n","sourceCodeStart":1329,"sourceCodeEnd":1365,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/brands/index.ts#L1329-L1365","documentation":"Thrown by finalizeBrand when JSON.parse(brandJsonRaw) failed AND extractJsonBlock(brandJsonRaw) could not find a fenced code block containing JSON. The file exists and has content, but it is neither parseable JSON nor a markdown fence the lenient extractor can recover. Distinct from error 34 (file absent) and error 36 (parses but fails schema).","triggerScenarios":"The agent wrote prose/markdown without a ```json fence; wrote truncated or partially-streamed JSON; wrote YAML or another format; the file was corrupted on write.","commonSituations":"Agent interrupted mid-write (partial flush); model returned commentary instead of structured output; concurrent writes or disk-full truncation.","solutions":["Open the project's brand.json and inspect the contents to see what the agent actually wrote.","Re-run the extraction so the agent writes a clean JSON file.","If the content is JSON wrapped in prose, wrap it in a ```json fence so extractJsonBlock can recover it (the lenient path)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function looksLikeJsonOrFence(raw: string): boolean {\n  const trimmed = raw.trim();\n  if (!trimmed) return false;\n  try { JSON.parse(trimmed); return true; } catch { /* fall through */ }\n  return /```(?:json)?[\\s\\S]*?```/i.test(trimmed);\n}\nconst raw = await readProjectTextOrNull(projectsRoot, projectId, 'brand.json');\nif (raw !== null && !looksLikeJsonOrFence(raw)) {\n  throw new Error('brand.json is neither valid JSON nor a fenced JSON block. Re-run the extraction.');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await finalizeBrand(opts);\n} catch (err) {\n  if (err instanceof Error && err.message === 'brand.json is not valid JSON.') {\n    return conflict('brand.json contents are malformed. Inspect the file or re-run the extraction.');\n  }\n  throw err;\n}","preventionTips":["Instruct the extraction agent to write raw JSON (or a clearly fenced ```json block) and nothing else.","Detect partial writes (file size growing) and wait before finalizing.","Keep the lenient fence-extractor path in mind — wrapping output in ```json lets it recover commentary-wrapped JSON."],"tags":["brands","validation","json","agent","finalize"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}