paperclipai/paperclip · error · Error
: missing local branding provenance
Error message
${slug}: missing local branding provenance What it means
brandingFor() resolves each app slug to a locally-hosted brand asset via ui/public/brands/apps/manifest.json. If the slug is not in the manifest and is not one of the two generic fallbacks (oauth-generic/api-key-generic), ingestion refuses to emit an AppDefinition without provenance, because a published app must ship a verifiable local logo rather than a remote or missing one.
Solutions
- Add (or fix the slug of) the provider entry in ui/public/brands/apps/manifest.json, including localAsset pointing at the bundled SVG under /brands/apps/.
- Verify the app slug in scripts/ingest-app-definitions.mjs matches the manifest slug exactly (case-sensitive), including darkAsset handling.
- Regenerate the branding manifest via the asset-export pipeline if a new provider asset was added but not ingested.
- If the app is intentionally generic (no real provider brand), use slug "oauth-generic" or "api-key-generic", which have hardcoded fallbacks.
Example fix
// before
slug: "slackapp"
// after (manifest.json providers entry must exist)
slug: "slack" // entry: { "slug": "slack", "localAsset": "/brands/apps/slack.svg" } Defensive patterns
Strategy: validation
Validate before calling
const manifest = JSON.parse(fs.readFileSync('ui/public/brands/apps/manifest.json','utf8'));
const slugs = new Set(manifest.providers.map(p => p.slug));
if (!slugs.has(slug) && !['oauth-generic','api-key-generic'].includes(slug)) {
throw new Error(`${slug}: add branding manifest entry before ingesting`);
} Type guard
const hasBranding = (slug) => typeof slug === 'string' && (genericSlugs.includes(slug) || brandingBySlug.has(slug));
Prevention
- Always add the manifest entry + SVG in the same PR as a new app definition.
- Add a CI check that diffs app slugs against manifest slugs.
- Keep slug names consistent via a single shared constant list.
When it happens
Trigger: Calling brandingFor(slug) (directly or via app-definition generation in scripts/ingest-app-definitions.mjs) with a slug that (a) has no entry in brandingBySlug (built from ui/public/brands/apps/manifest.json 'providers' keyed by 'slug'), and (b) is not exactly "oauth-generic" or "api-key-generic".
Common situations: Adding a new app definition without first exporting its brand asset and regenerating the branding manifest; a slug typo or rename in the app definition that no longer matches the manifest slug; manually editing manifest.json and dropping a provider entry; running the ingest script in a checkout where ui/public/brands/apps/manifest.json is stale or truncated.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- : missing provider name
- : capture has no states
- / / : required field needs placeholder
- / : oauth requires ownershipModes
- / : tool api_key requires keyPlacement
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/41d53824af90babf.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/ingest-app-definitions.mjs:32
const brandingManifest = JSON.parse(
fs.readFileSync(
path.join(root, "ui/public/brands/apps/manifest.json"),
"utf8",
),
);
const brandingBySlug = new Map(
brandingManifest.providers.map((entry) => [entry.slug, entry]),
);
const brandingFor = (slug) => {
const entry = brandingBySlug.get(slug);
if (entry)
return {
logoUrl: entry.localAsset,
...(entry.darkAsset ? { darkLogoUrl: entry.darkAsset } : {}),
};
if (slug === "oauth-generic" || slug === "api-key-generic")
return { logoUrl: `/brands/apps/${slug}.svg` };
throw new Error(`${slug}: missing local branding provenance`);
};
const field = (key, label, placeholder) => ({
key,
label,
type: "password",
required: true,
placeholder,
secret: true,
});
const method = (
key,
transport,
auth,
defaults,
riskTier,
guidanceMd,
extra = {},
) => ({View on GitHub (pinned to 3f1d897a7c)