{"record":{"id":"6f188cf384b30453","repo":"paperclipai/paperclip","slug":"row-slug-missing-provider-name","errorCode":null,"errorMessage":"${row.slug}: missing provider name","messagePattern":"(.+?): missing provider name","errorType":"console","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/app-brand-validation.mjs","lineNumber":33,"sourceCode":"  const svg = bytes.toString(\"utf8\");\n  if (!filename.endsWith(\".svg\") || (!/<svg\\b[^>]*\\bviewBox\\s*=\\s*[\"'][^\"']+[\"']/i.test(svg) && !(/<svg\\b[^>]*\\bwidth\\s*=\\s*[\"'][0-9.]+(?:px)?[\"']/i.test(svg) && /<svg\\b[^>]*\\bheight\\s*=\\s*[\"'][0-9.]+(?:px)?[\"']/i.test(svg)))) {\n    throw new Error(`${filename}: SVG requires a viewBox or intrinsic width and height`);\n  }\n  if (/<!DOCTYPE|<!ENTITY|<\\?xml-stylesheet|&#|<\\s*(?:[\\w-]+:)?(?:script|foreignObject|image|feImage|iframe|object|embed|animate\\w*|set|a)\\b|\\bon[\\w-]+\\s*=/i.test(svg)\n    || /\\b(?:[\\w-]+:)?href\\s*=\\s*[\"'](?!#)/i.test(svg)\n    || /@import|@media|url\\(\\s*[\"']?(?!#)[^)]*\\)|(?:javascript|data|https?):|\\\\/i.test(svg.replace(/xmlns(?::[\\w-]+)?\\s*=\\s*[\"'][^\"']*[\"']/gi, \"\"))) {\n    throw new Error(`${filename}: unsafe SVG feature, external resource, theme media query, or embedded raster wrapper`);\n  }\n}\n\nexport function validateManifest(manifest, readAsset) {\n  if (manifest.schemaVersion !== 1 || !Array.isArray(manifest.providers)) throw new Error(\"Invalid brand manifest\");\n  const keys = new Map();\n  const slugs = new Set();\n  for (const row of manifest.providers) {\n    if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(row.slug) || slugs.has(row.slug)) throw new Error(`Duplicate or invalid slug: ${row.slug}`);\n    slugs.add(row.slug);\n    if (typeof row.provider !== \"string\" || !row.provider.trim()) throw new Error(`${row.slug}: missing provider name`);\n    const aliases = row.aliases ?? [];\n    if (!Array.isArray(aliases) || aliases.some((alias) => typeof alias !== \"string\" || !alias.trim())) throw new Error(`${row.slug}: invalid aliases`);\n    for (const name of [row.slug, row.provider, ...aliases]) {\n      const key = normalizeBrandKey(name);\n      if (keys.has(key) && keys.get(key) !== row.slug) throw new Error(`${row.slug}: ambiguous brand alias ${name}`);\n      keys.set(key, row.slug);\n    }\n    for (const asset of new Set([row.localAsset, ...(row.darkAsset === undefined ? [] : [row.darkAsset])])) {\n      if (typeof asset !== \"string\" || !assetPathPattern.test(asset)) throw new Error(`${row.slug}: invalid asset path`);\n      validateArtwork(readAsset(asset), asset);\n    }\n  }\n  return manifest.providers.length;\n}\n","sourceCodeStart":15,"sourceCodeEnd":48,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/scripts/app-brand-validation.mjs#L15-L48","documentation":"The app brand validation script throws this when a provider row in the brand manifest has a provider field that is not a non-empty string (missing, non-string, or whitespace-only). Every provider entry must carry a human-readable provider name.","triggerScenarios":"Running validateManifest on a manifest whose providers[] entry omits the `provider` key, sets it to a non-string value, or sets it to \"\" or whitespace.","commonSituations":"Hand-editing the brand manifest and forgetting the provider field; a code generation step that writes an empty provider; a new catalog entry scaffolded without a provider name.","solutions":["Add a non-empty provider string to the offending row identified by the slug in the message.","Fix typos where provider was written under a different key name (e.g. `name` instead of `provider`).","Re-run scripts/app-brand-validation.mjs to confirm the manifest validates."],"exampleFix":"// before\n{ \"slug\": \"acme\", \"aliases\": [\"Acme Corp\"] }\n// after\n{ \"slug\": \"acme\", \"provider\": \"Acme Corporation\", \"aliases\": [\"Acme Corp\"] }","handlingStrategy":"validation","validationCode":"const bad = manifest.providers.filter(r => typeof r.provider !== 'string' || !r.provider.trim());\nif (bad.length) throw new Error(`Missing provider name for: ${bad.map(r => r.slug)}`);","typeGuard":"const hasProviderName = (row) => typeof row?.provider === 'string' && row.provider.trim().length > 0;","tryCatchPattern":"try { validateManifest(manifest); } catch (e) {\n  if (e.message.includes('missing provider name')) {\n    const slug = e.message.split(':')[0];\n    console.error(`Fill in provider name for ${slug} in the brand manifest`);\n  } else throw e;\n}","preventionTips":["Use a JSON schema or typed interface for brand manifest rows so missing provider fails typecheck.","Run the brand validation script in CI before merging manifest changes.","Scaffold new provider rows from a template that includes provider."],"tags":["manifest","validation","branding","schema"],"backgroundTag":"empty-required-field","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}