{"record":{"id":"51c38260c6eec7ad","repo":"thedotmack/claude-mem","slug":"invalid-corpus-name","errorCode":"INVALID_CORPUS_NAME","errorMessage":"Invalid corpus name: only alphanumeric characters, dots, hyphens, and underscores are allowed","messagePattern":"Invalid corpus name: only alphanumeric characters, dots, hyphens, and underscores are allowed","errorType":"validation","errorClass":"AppError","httpStatus":400,"severity":"warning","filePath":"src/services/worker/knowledge/CorpusStore.ts","lineNumber":100,"sourceCode":"\n    return results;\n  }\n\n  delete(name: string): boolean {\n    const filePath = this.getFilePath(name);\n    if (!fs.existsSync(filePath)) {\n      return false;\n    }\n\n    fs.unlinkSync(filePath);\n    logger.debug('WORKER', `Deleted corpus file: ${filePath}`);\n    return true;\n  }\n\n  private validateCorpusName(name: string): string {\n    const trimmed = name.trim();\n    if (!CORPUS_NAME_PATTERN.test(trimmed)) {\n      throw new AppError(CORPUS_NAME_ERROR, 400, 'INVALID_CORPUS_NAME');\n    }\n    return trimmed;\n  }\n\n  private getFilePath(name: string): string {\n    const safeName = this.validateCorpusName(name);\n    const resolved = path.resolve(this.corporaDir, `${safeName}.corpus.json`);\n    if (!resolved.startsWith(path.resolve(this.corporaDir) + path.sep)) {\n      throw new AppError('Invalid corpus name', 400, 'INVALID_CORPUS_NAME');\n    }\n    return resolved;\n  }\n}\n","sourceCodeStart":82,"sourceCodeEnd":114,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/services/worker/knowledge/CorpusStore.ts#L82-L114","documentation":"Thrown by CorpusStore.validateCorpusName when a corpus name (after trim) does not match /^[a-zA-Z0-9._-]+$/ . It is an AppError with HTTP 400 and code INVALID_CORPUS_NAME — a client-side input mistake, not a server fault. Names with spaces, slashes, or non-ASCII are rejected to keep file paths safe.","triggerScenarios":"Any CorpusStore operation (write/read/list/delete) receiving a name containing spaces, '/', '\\\\', colons, or non-ASCII characters; e.g., POSTing a corpus with name 'my corpus' or 'a/b'.","commonSituations":"User-typed corpus name with a space; UI passing an untrimmed title; API client sending a path-like name; copy-paste introducing unicode dashes/quotes.","solutions":["Sanitize the name client-side to alphanumeric, '.', '-', '_' only before sending.","Trim whitespace and replace spaces with hyphens or underscores.","Validate against CORPUS_NAME_PATTERN (/^[a-zA-Z0-9._-]+$/) in the API layer and return a friendly 400 before reaching CorpusStore."],"exampleFix":"// before\nconst name = userInput; // 'my corpus v2'\nstore.write({ name, ... });\n\n// after\nimport { CORPUS_NAME_PATTERN } from './CorpusStore';\nconst name = userInput.trim().replace(/\\s+/g, '-');\nif (!CORPUS_NAME_PATTERN.test(name)) {\n  throw new Error(`Invalid corpus name: ${name}`);\n}\nstore.write({ name, ... });","handlingStrategy":"validation","validationCode":"import { CORPUS_NAME_PATTERN } from './CorpusStore';\nfunction isValidCorpusName(name: string): boolean {\n  return CORPUS_NAME_PATTERN.test(name.trim());\n}\nif (!isValidCorpusName(name)) {\n  return res.status(400).json({ error: 'Invalid corpus name' });\n}","typeGuard":"function isCorpusName(name: string): boolean {\n  return typeof name === 'string' && /^[a-zA-Z0-9._-]+$/.test(name.trim());\n}","tryCatchPattern":"try {\n  store.write(corpus);\n} catch (err) {\n  if (err instanceof AppError && err.code === 'INVALID_CORPUS_NAME') {\n    return res.status(400).json({ error: err.message });\n  }\n  throw err;\n}","preventionTips":["Validate corpus names in the API/UI layer before reaching CorpusStore.","Normalize user input: trim and replace whitespace with '-' or '_'.","Reuse the exported CORPUS_NAME_PATTERN so validation stays in sync with the store."],"tags":["validation","corpus","input-sanitization","http-400"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}