nexu-io/open-design · error
brand backing project not found: ${projectId}
Error message
brand backing project not found: ${projectId} What it means
Thrown by continueBrandExtraction when the brand meta exists but getProject(db, projectId) returns null, meaning the SQLite project row backing the brand is gone. The on-disk brand survived but the project database was reset, dropped, or surgically modified. Indicates a data-integrity split between filesystem and DB.
Source
Thrown at apps/daemon/src/brands/index.ts:694
extractionSettled = true;
clearTimeout(stallTimer);
clearTimeout(hardCapTimer);
});
input.onBackgroundExtraction?.(settled);
return settled;
}
export async function continueBrandExtraction(
opts: ContinueBrandExtractionOptions,
): Promise<StartBrandExtractionResult> {
const detail = readBrandDetail(opts.brandsRoot, opts.id);
if (!detail) throw new Error(`brand not found: ${opts.id}`);
const { meta } = detail;
const sourceUrl = meta.sourceUrl;
const projectId = meta.projectId ?? brandProjectId(opts.id);
const project = getProject(opts.db, projectId);
if (!project) throw new Error(`brand backing project not found: ${projectId}`);
const randomId = opts.randomId ?? randomUUID;
const locale = normalizeBrandKitLocale(opts.locale ?? meta.locale);
const hasWebsiteSource = /^https?:\/\//i.test(sourceUrl);
const designMd = readDesignMdInput(opts.brandsRoot, opts.id);
const hasDesignMdSource = Boolean(designMd) || sourceUrl.startsWith('designmd://');
const host = hostnameOf(sourceUrl);
const now = Date.now();
const extractionAttemptId = newBrandExtractionAttemptId();
const conversationId = resolveBrandRetryConversationId({
db: opts.db,
projectId,
preferredConversationId: meta.conversationId ?? null,
randomId,
now,
});
let nextMeta = patchMeta(opts.brandsRoot, opts.id, {View on GitHub (pinned to 5be4028344)
Solutions
- Restore the project database so the backing project row exists again.
- Re-create the backing project and update the brand meta's projectId to match.
- If reconciliation is not possible, re-run startBrandExtraction to create a fresh brand + project pair and delete the orphaned brand.
Defensive patterns
Strategy: validation
Validate before calling
const detail = readBrandDetail(brandsRoot, opts.id);
if (!detail) throw new NotFoundError(`brand not found: ${opts.id}`);
const projectId = detail.meta.projectId ?? brandProjectId(opts.id);
const project = getProject(db, projectId);
if (!project) {
throw new DataIntegrityError(`Brand '${opts.id}' has no backing project row '${projectId}'. Re-create the brand or restore the project DB.`);
} Try / catch
try {
await continueBrandExtraction(opts);
} catch (err) {
if (err instanceof Error && /^brand backing project not found:/.test(err.message)) {
return conflict('Backing project is gone. Re-run startBrandExtraction to recreate it.');
}
throw err;
} Prevention
- Back up the SQLite project DB alongside the brands directory so they restore together.
- Never delete project rows manually without also removing the brand meta.
- After a DB restore, run a reconciliation pass that orphans brands whose project rows are missing.
When it happens
Trigger: The SQLite DB was wiped or restored from an older backup while the brands directory was left intact; someone manually deleted the project row; the project DB file was moved.
Common situations: Partial data restore (DB restored without the brands dir, or vice versa); manual DB surgery; a migration that dropped project rows but not brands.
Related errors
- brand not found: ${opts.id}
- brand not found: ${id}
- automation proposal not found
- Could not fetch ${url} — the site may block server-side requ
- Enter a valid http(s) website URL.
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/49c6df594eaf64fb.
Report an issue: GitHub.