nexu-io/open-design · error · Error
invalid brand id: ${input.brandId}
Error message
invalid brand id: ${input.brandId} What it means
Thrown by syncBrandFilesToProject when resolveBrandFile(brandsRoot, input.brandId, []) returns null. This is a path-safety/slug guard, NOT a not-found check: the brand id failed validation (contains '..', slashes, or characters outside the allowed set) and was refused before directory lookup. Security-relevant: it blocks path traversal.
Source
Thrown at apps/daemon/src/brands/index.ts:2107
return;
}
const source = path.join(projectDir, dirName);
if (!isDirectory(source)) return;
const target = resolveBrandFile(brandsRoot, brandId, [dirName]);
if (!target) return;
copyDirectorySync(source, target);
}
async function syncBrandFilesToProject(input: {
brandsRoot: string;
projectsRoot: string;
brandId: string;
projectId: string;
brand: Brand;
metadata: ProjectMetadata;
}): Promise<void> {
const brandRoot = resolveBrandFile(input.brandsRoot, input.brandId, []);
if (!brandRoot) throw new Error(`invalid brand id: ${input.brandId}`);
const write = async (name: string, body: string | Buffer) => {
await writeProjectFile(input.projectsRoot, input.projectId, name, body, { overwrite: true }, input.metadata);
};
await write('brand.json', JSON.stringify(input.brand, null, 2));
await write('DESIGN.md', brandToDesignMd(input.brand));
await writeOptionalFileToProject(input.projectsRoot, input.projectId, input.metadata, brandRoot, 'guide.md');
await copyDirectoryToProject(input.projectsRoot, input.projectId, input.metadata, brandSystemDir(input.brandsRoot, input.brandId), 'system');
await copyOptionalDirectoryToProject(input.projectsRoot, input.projectId, input.metadata, path.join(brandRoot, 'logos'), 'logos');
await copyOptionalDirectoryToProject(input.projectsRoot, input.projectId, input.metadata, path.join(brandRoot, 'fonts'), 'fonts');
await copyOptionalDirectoryToProject(input.projectsRoot, input.projectId, input.metadata, path.join(brandRoot, 'imagery'), 'imagery');
await copyOptionalDirectoryToProject(input.projectsRoot, input.projectId, input.metadata, path.join(brandRoot, 'prefetch'), 'prefetch');
await copyOptionalDirectoryToProject(input.projectsRoot, input.projectId, input.metadata, path.join(brandRoot, 'context'), 'context');
}
async function writeOptionalFileToProject(
projectsRoot: string,
projectId: string,
metadata: ProjectMetadata,View on GitHub (pinned to 5be4028344)
Solutions
- Use only safe slug brand ids produced by the brand-creation flow.
- Reject any id containing '/', '\', or '..' before calling syncBrandFilesToProject.
- If accepting user input, slugify and validate against a strict character set upstream.
Defensive patterns
Strategy: validation
Validate before calling
function isSafeBrandId(id: string): boolean {
// Mirror resolveBrandFile's contract: no path separators, no parent traversal.
return typeof id === 'string' && id.length > 0 && !/[\\/]/.test(id) && !/(^|\/|\\)\.\.?(\/|\\|$)/.test(id);
}
if (!isSafeBrandId(input.brandId)) {
throw new Error(`Refusing to sync: brand id '${input.brandId}' is not a safe slug.`);
} Type guard
function isSafeBrandId(id: unknown): id is string {
return typeof id === 'string'
&& id.length > 0
&& !/[\\/]/.test(id)
&& id !== '..'
&& !id.includes('../');
} Try / catch
try {
await syncBrandFilesToProject(input);
} catch (err) {
if (err instanceof Error && err.message.startsWith('invalid brand id:')) {
return badRequest('Brand id must be a safe slug with no path characters.');
}
throw err;
} Prevention
- Never build brand ids from raw URL path segments — slugify and validate first.
- Reject any id containing '/', '\\', or '..' at the trust boundary.
- Treat this error as a security signal: path-traversal attempts should be logged, not just returned.
When it happens
Trigger: Passing a brandId containing path separators ('../x', 'a/b'), parent traversal ('..'), or characters the resolver rejects; constructing an id from untrusted URL path input without sanitization.
Common situations: User-supplied or URL-derived brand id reaching the sync path unsanitized; programmatic callers concatenating path segments into the id; testing with literal traversal strings.
Related errors
- invalid design system id: ${designSystemId}
- --image path "${rel}" resolves outside the project directory
- invalid memory id
- path traversal detected in input_images for job {job.get('id
- path traversal detected in prompt_file for job {job_id}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/fc1a80e42226e387.
Report an issue: GitHub.