nexu-io/open-design · error · Error
brand: missing required `name`
Error message
brand: missing required `name`
What it means
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`.
Source
Thrown at apps/daemon/src/brands/validate.ts:55
return {
family: isStr(o.family) && o.family ? o.family : fallbackFamily,
fallbacks: strArr(o.fallbacks),
weights: Array.isArray(o.weights) ? o.weights.filter((w) => typeof w === 'number') : [400, 700],
...(isStr(o.googleFontsUrl) && o.googleFontsUrl ? { googleFontsUrl: o.googleFontsUrl } : {}),
...(isStr(o.notes) && o.notes ? { notes: o.notes } : {}),
};
}
/**
* Validate + normalize a brand object. Throws with a precise message on
* unrecoverable problems (missing name/colors); fills sensible defaults for
* everything optional so a slightly-sloppy input still renders.
*/
export function validateBrand(raw: unknown, sourceUrl: string): Brand {
if (!raw || typeof raw !== 'object') throw new Error('brand is not a JSON object');
const o = raw as Record<string, unknown>;
if (!isStr(o.name) || !o.name.trim()) throw new Error('brand: missing required `name`');
const rawColors = Array.isArray(o.colors) ? o.colors : [];
const colors: BrandColor[] = [];
for (const c of rawColors) {
if (!c || typeof c !== 'object') continue;
const co = c as Record<string, unknown>;
const role = BRAND_COLOR_ROLES.includes(co.role as BrandColorRole)
? (co.role as BrandColorRole)
: null;
const hex = isStr(co.hex) && /^#[0-9a-fA-F]{6}$/.test(co.hex) ? co.hex.toLowerCase() : null;
if (!role || !hex) continue;
colors.push({
role,
hex,
oklch: isStr(co.oklch) ? co.oklch : '',
name: isStr(co.name) ? co.name : role,
usage: isStr(co.usage) ? co.usage : '',
});View on GitHub (pinned to 5be4028344)
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.
Example fix
// before const o = raw as Record<string, unknown>; const brand = validateBrand(o, sourceUrl); // after — normalize synonyms before validation if (!o.name) o.name = o.brandName ?? o.title ?? o.company; const brand = validateBrand(o, sourceUrl);
Defensive patterns
Strategy: validation
Validate before calling
if (!o.name) o.name = o.brandName ?? o.title ?? o.company;
if (typeof o.name !== 'string' || !o.name.trim()) {
throw new Error('brand: missing required `name`');
} Type guard
const hasBrandName = (o: Record<string, unknown>): boolean => typeof o.name === 'string' && o.name.trim().length > 0;
Prevention
- 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.
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- brand: `colors` must include at least the background, foregr
- brand is not a JSON object
- brand.json failed validation: ${errorMessage(err)}
- invalid brand id: ${brandId}
- invalid brand id: ${id}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/c9ae3b9d10508566.
Report an issue: GitHub.