nexu-io/open-design · error

brand not found: ${opts.id}

Error message

brand not found: ${opts.id}

What it means

Thrown by continueBrandExtraction when readBrandDetail(brandsRoot, opts.id) returns null, i.e. no brand directory/meta exists for that id. The route handler maps /not found/i to HTTP 404.

Source

Thrown at apps/daemon/src/brands/index.ts:689

      if (isClosedDatabaseError(err)) return null;
      console.warn(`[brand] failed to reconcile programmatic extraction transcript for ${id}`, err);
      return null;
    })
    .finally(() => {
      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,

View on GitHub (pinned to 5be4028344)

Solutions

  1. List brands via the brand list endpoint to confirm the id exists.
  2. If the brand was deleted, start a new extraction with startBrandExtraction instead of continue.
  3. Verify the daemon is using the expected brandsRoot (OD_DATA_DIR / RUNTIME_DATA_DIR).
Defensive patterns

Strategy: validation

Validate before calling

const detail = readBrandDetail(brandsRoot, opts.id);
if (!detail) {
  throw new NotFoundError(`No brand with id '${opts.id}'. Create one with startBrandExtraction first.`);
}

Type guard

function isExistingBrand(detail: unknown): detail is BrandDetailResponse {
  return detail !== null && detail !== undefined;
}

Try / catch

try {
  await continueBrandExtraction(opts);
} catch (err) {
  if (err instanceof Error && /^brand not found:/.test(err.message)) {
    return notFound('That brand no longer exists. Start a new extraction.');
  }
  throw err;
}

Prevention

When it happens

Trigger: Continuing an extraction for a brand id that was deleted, never created, or was mistyped; the brandsRoot was changed/relocated between requests.

Common situations: Restarting after clearing the data directory; a stale client link from a previous session; copy-paste error in the id.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/4381ba783a674276. Report an issue: GitHub.