paperclipai/paperclip · error · Error
: invalid asset path
Error message
${row.slug}: invalid asset path What it means
The app brand validation script throws this when a provider row's localAsset (or darkAsset) is not a string or does not match the manifest's assetPathPattern. Asset paths must follow the expected layout so the validator can read and inspect the artwork.
Solutions
- Correct the asset path to match the required assetPathPattern (check other rows for the expected format).
- Ensure the referenced file actually exists at that path in the package.
- Remove an unused darkAsset field rather than leaving an invalid value.
- Re-run the validation script.
Example fix
// before "localAsset": "/abs/path/logo.svg" // after "localAsset": "assets/acme/logo.svg"
Defensive patterns
Strategy: validation
Validate before calling
const pattern = /^assets\/[a-z0-9-]+\/[a-z0-9-]+\.svg$/; // match assetPathPattern
for (const r of manifest.providers)
for (const a of [r.localAsset, r.darkAsset].filter(Boolean))
if (typeof a !== 'string' || !pattern.test(a)) throw new Error(`${r.slug}: bad asset path ${a}`); Type guard
const hasValidAssetPath = (row, pattern) => typeof row?.localAsset === 'string' && pattern.test(row.localAsset) && (row.darkAsset === undefined || (typeof row.darkAsset === 'string' && pattern.test(row.darkAsset)));
Try / catch
try { validateManifest(manifest); } catch (e) {
if (e.message.includes('invalid asset path')) {
const slug = e.message.split(':')[0];
console.error(`Fix asset path format for ${slug} to match assetPathPattern`);
} else throw e;
} Prevention
- Keep asset files under the expected directory layout and use relative paths only.
- Never use absolute paths or ../ segments in asset fields.
- Update manifest paths whenever asset files are renamed; do it in the same commit.
When it happens
Trigger: Running validateManifest where row.localAsset or row.darkAsset is missing/non-string, or is a string that fails assetPathPattern (wrong directory, wrong extension, absolute path, or path traversal style).
Common situations: Renaming asset files without updating the manifest; using an absolute path or ../ escape; adding a darkAsset with a path that doesn't follow the pattern; typos in the extension.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- CreateOS transfer requires an absolute host path.
- Invalid or oversized current.json
- Invalid PAPERCLIP_PAGE_DEFAULT_PREFIX: use lowercase path…
- : ambiguous brand alias
- : invalid aliases
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/51e0a5c1d753734a.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/app-brand-validation.mjs:42
}
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)