thedotmack/claude-mem · warning · AppError
INVALID_CORPUS_NAME
INVALID_CORPUS_NAME
Error message
Invalid corpus name: only alphanumeric characters, dots, hyphens, and underscores are allowed
What it means
CorpusStore.validateCorpusName rejects corpus names not matching /^[a-zA-Z0-9._-]+$/ (after trim) and throws an AppError with code INVALID_CORPUS_NAME and HTTP 400. This guards the filesystem: the name is used directly in `${safeName}.corpus.json` file paths, so slashes, spaces, and unicode would either break the file layout or enable path traversal.
Solutions
- Rename the corpus to contain only alphanumerics, dots, hyphens, and underscores
- Sanitize user input before passing it to the corpus API (strip or encode disallowed characters)
- Return the 400 INVALID_CORPUS_NAME to the caller with the allowed character set so they can correct it
- Handle the empty-string case explicitly before calling the store to give a clearer message
Example fix
// before await store.create(userInputName, content); // 'my corpus' → throws // after const safe = userInputName.trim().replace(/[^a-zA-Z0-9._-]/g, '-'); await store.create(safe, content);
Defensive patterns
Strategy: validation
Validate before calling
const CORPUS_NAME_RE = /^[a-zA-Z0-9._-]+$/;
function isValidCorpusName(name: unknown): name is string {
return typeof name === 'string' && name.trim().length > 0 && CORPUS_NAME_RE.test(name.trim());
} Type guard
function isValidCorpusName(name: unknown): name is string {
return typeof name === 'string' && /^[a-zA-Z0-9._-]+$/.test(name.trim());
} Try / catch
try {
await store.create(name, content);
} catch (err) {
if (err instanceof AppError && err.code === 'INVALID_CORPUS_NAME') {
// surface 400 to the user with the allowed character set
return res.status(400).json({ error: 'Corpus name may only contain a-z, A-Z, 0-9, dot, hyphen, underscore' });
}
throw err;
} Prevention
- Sanitize or slugify user-supplied names before passing to the corpus API
- Validate names at the CLI/HTTP boundary, not just inside the store
- Document the allowed character set where users enter corpus names
- Reject empty/whitespace names with a distinct message before calling the store
When it happens
Trigger: Creating, reading, or writing a corpus whose name contains characters outside [a-zA-Z0-9._-] — e.g. 'my corpus', 'corp/us', 'café', or an empty/whitespace-only name.
Common situations: User-supplied corpus names passed through from a CLI flag or HTTP request; names built by string concatenation from file paths; locale/unicode names pasted from other tools; a name that is only whitespace after trim.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Refusing awareness write outside agent memory/log
- Refusing awareness write to profile.md
- Refusing CCS Align write outside the seat-owned ccs-align…
- Refusing CCS Align write to profile.md
- Adapter rejected input
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/51c38260c6eec7ad.
Report an issue: GitHub.
Appendix: source
Thrown at src/services/worker/knowledge/CorpusStore.ts:100
return results;
}
delete(name: string): boolean {
const filePath = this.getFilePath(name);
if (!fs.existsSync(filePath)) {
return false;
}
fs.unlinkSync(filePath);
logger.debug('WORKER', `Deleted corpus file: ${filePath}`);
return true;
}
private validateCorpusName(name: string): string {
const trimmed = name.trim();
if (!CORPUS_NAME_PATTERN.test(trimmed)) {
throw new AppError(CORPUS_NAME_ERROR, 400, 'INVALID_CORPUS_NAME');
}
return trimmed;
}
private getFilePath(name: string): string {
const safeName = this.validateCorpusName(name);
const resolved = path.resolve(this.corporaDir, `${safeName}.corpus.json`);
if (!resolved.startsWith(path.resolve(this.corporaDir) + path.sep)) {
throw new AppError('Invalid corpus name', 400, 'INVALID_CORPUS_NAME');
}
return resolved;
}
}
View on GitHub (pinned to d8bc9755e7)