paperclipai/paperclip · error · Error
: ambiguous brand alias
Error message
${row.slug}: ambiguous brand alias ${name} What it means
The app brand validation script throws this when two different provider rows normalize to the same brand key via normalizeBrandKey (slug, provider name, or any alias colliding across rows). Ambiguous aliases would make brand lookups non-deterministic, so the manifest is rejected.
Solutions
- Find the colliding name from the message and change the alias on the newer row to something unambiguous.
- If both rows genuinely refer to the same provider, merge the rows instead of duplicating.
- Check normalization rules (case/punctuation folding) and pick a name that stays distinct after normalization.
- Re-run the validation script to confirm no further collisions.
Example fix
// before (collides with provider "acme")
{ "slug": "acme-cloud", "provider": "Acme Cloud", "aliases": ["Acme"] }
// after
{ "slug": "acme-cloud", "provider": "Acme Cloud", "aliases": ["Acme Cloud Platform"] } Defensive patterns
Strategy: validation
Validate before calling
function norm(s){return s.toLowerCase().replace(/[^a-z0-9]/g,'');}
const seen = new Map();
for (const r of manifest.providers)
for (const n of [r.slug, r.provider, ...(r.aliases ?? [])]) {
const k = norm(n);
if (seen.has(k) && seen.get(k) !== r.slug) throw new Error(`Ambiguous alias ${n}`);
seen.set(k, r.slug);
} Try / catch
try { validateManifest(manifest); } catch (e) {
if (e.message.includes('ambiguous brand alias')) {
console.error('Rename or merge the colliding provider/alias before retrying');
} else throw e;
} Prevention
- Search the existing manifest (including aliases) before adding a new provider name.
- Prefer fully qualified brand names as aliases to reduce normalization collisions.
- Run validation in CI to catch collisions at PR time.
When it happens
Trigger: Running validateManifest where row A's slug/provider/alias normalizes to the same key as row B's (keys.has(key) && keys.get(key) !== row.slug), e.g. two providers aliasing "GitHub" or a provider name equal to another row's slug.
Common situations: Adding a new provider whose alias duplicates an existing brand; case/spacing variants like "acme" vs "Acme" normalizing to the same key; renaming a provider so it now collides with another slug.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Evalbook attempt identity is empty
- Invalid or oversized current.json
- : invalid aliases
- : invalid asset path
- : missing provider name
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/01f918f49eeeca12.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/app-brand-validation.mjs:38
|| /\b(?:[\w-]+:)?href\s*=\s*["'](?!#)/i.test(svg)
|| /@import|@media|url\(\s*["']?(?!#)[^)]*\)|(?:javascript|data|https?):|\\/i.test(svg.replace(/xmlns(?::[\w-]+)?\s*=\s*["'][^"']*["']/gi, ""))) {
throw new Error(`${filename}: unsafe SVG feature, external resource, theme media query, or embedded raster wrapper`);
}
}
export function validateManifest(manifest, readAsset) {
if (manifest.schemaVersion !== 1 || !Array.isArray(manifest.providers)) throw new Error("Invalid brand manifest");
const keys = new Map();
const slugs = new Set();
for (const row of manifest.providers) {
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(row.slug) || slugs.has(row.slug)) throw new Error(`Duplicate or invalid slug: ${row.slug}`);
slugs.add(row.slug);
if (typeof row.provider !== "string" || !row.provider.trim()) throw new Error(`${row.slug}: missing provider name`);
const aliases = row.aliases ?? [];
if (!Array.isArray(aliases) || aliases.some((alias) => typeof alias !== "string" || !alias.trim())) throw new Error(`${row.slug}: invalid aliases`);
for (const name of [row.slug, row.provider, ...aliases]) {
const key = normalizeBrandKey(name);
if (keys.has(key) && keys.get(key) !== row.slug) throw new Error(`${row.slug}: ambiguous brand alias ${name}`);
keys.set(key, row.slug);
}
for (const asset of new Set([row.localAsset, ...(row.darkAsset === undefined ? [] : [row.darkAsset])])) {
if (typeof asset !== "string" || !assetPathPattern.test(asset)) throw new Error(`${row.slug}: invalid asset path`);
validateArtwork(readAsset(asset), asset);
}
}
return manifest.providers.length;
}
View on GitHub (pinned to 3f1d897a7c)