thedotmack/claude-mem · error

Corpus "${name}" not found

Error message

Corpus "${name}" not found

What it means

HTTP 404 from CorpusRoutes.corpusNotFound, returned by every /api/corpus/:name handler (GET, DELETE, rebuild, prime, query, reprime) when the named corpus is not in the in-memory corpus store. The body is richer than a plain 404: it includes a fix hint and an available array listing corpora that do exist, so the correct name is one field away.

Source

Thrown at src/services/worker/http/routes/CorpusRoutes.ts:84

    private corpusBuilder: CorpusBuilder,
    private knowledgeAgent: KnowledgeAgent
  ) {
    super();
  }

  setupRoutes(app: express.Application): void {
    app.post('/api/corpus', validateBody(buildCorpusSchema), this.handleBuildCorpus.bind(this));
    app.get('/api/corpus', this.handleListCorpora.bind(this));
    app.get('/api/corpus/:name', this.handleGetCorpus.bind(this));
    app.delete('/api/corpus/:name', this.handleDeleteCorpus.bind(this));
    app.post('/api/corpus/:name/rebuild', this.handleRebuildCorpus.bind(this));
    app.post('/api/corpus/:name/prime', this.handlePrimeCorpus.bind(this));
    app.post('/api/corpus/:name/query', validateBody(queryCorpusSchema), this.handleQueryCorpus.bind(this));
    app.post('/api/corpus/:name/reprime', this.handleReprimeCorpus.bind(this));
  }

  private corpusNotFound(res: Response, name: string): void {
    res.status(404).json({
      error: `Corpus "${name}" not found`,
      fix: 'Check the corpus name or build a new one',
      available: this.corpusStore.list().map(c => c.name)
    });
  }

  private handleBuildCorpus = this.wrapHandler(async (req: Request, res: Response): Promise<void> => {
    const { name, description, project, types, concepts, files, query, date_start, date_end, limit } =
      req.body as z.infer<typeof buildCorpusSchema>;

    const filter: CorpusFilter = {};
    if (project) filter.project = project;
    if (types && types.length > 0) filter.types = types as CorpusFilter['types'];
    if (concepts && concepts.length > 0) filter.concepts = concepts;
    if (files && files.length > 0) filter.files = files;
    if (query) filter.query = query;
    if (date_start) filter.date_start = date_start;
    if (date_end) filter.date_end = date_end;

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Read the available array in the 404 body and use one of those exact names
  2. If none exist, build one first: POST /api/corpus with the desired filter (project, concepts, files, date range)
  3. Check for case/exact-match differences — lookup is by exact name string

Example fix

// before
const r = await fetch(`${base}/api/corpus/Default/query`, { method: 'POST', body: JSON.stringify({ q: 'hooks' }) });
// 404: available: ["default-project"]

// after
const r = await fetch(`${base}/api/corpus/default-project/query`, { method: 'POST', body: JSON.stringify({ q: 'hooks' }) });
Defensive patterns

Strategy: validation

Validate before calling

async function firstAvailableCorpus(base: string, fallback?: string): Promise<string | undefined> {
  const list = await (await fetch(`${base}/api/corpus`)).json();
  const names: string[] = (list.corpora ?? []).map((c: { name: string }) => c.name);
  return names.includes(fallback ?? '') ? fallback : names[0];
}

Type guard

interface CorpusNotFoundBody {
  error: string;
  fix: string;
  available: string[];
}
function isCorpusNotFound(body: unknown, status: number): body is CorpusNotFoundBody {
  return status === 404 && Array.isArray((body as { available?: unknown })?.available);
}

Try / catch

const res = await callApi();
if (res.status === 404) {
  const body = await res.json();
  if (isCorpusNotFound(body, res.status))
    return retryWith(body.available[0]); // self-heal using the provided list
  throw new Error('corpus route failed');
}

Prevention

When it happens

Trigger: Querying or rebuilding a corpus name that was never built, was deleted, or whose build failed earlier; case mismatches in the name; using an id instead of the human name.

Common situations: Prompts or scripts hardcoding a corpus name like 'default' after the user renamed or removed it; querying right after a fresh install where no corpus exists yet; a build that appeared to succeed but actually errored.

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/853fd942f566da55. Report an issue: GitHub.