mastra-ai/mastra · error
Configured domain path "${directory}" is a file, expected a
Error message
Configured domain path "${directory}" is a file, expected a directory What it means
After passing the traversal check, listDomainFiles() stats the resolved directory and throws if it exists but is a regular file instead of a directory. The storage expects each domain path to be a directory of JSON files.
Source
Thrown at packages/core/src/storage/filesystem-db.ts:111
renameSync(tmpPath, filePath);
}
/**
* Clear all data from a domain JSON file.
*/
clearDomain(filename: string): void {
this.writeDomain(filename, {});
}
listDomainFiles(directory: string, extension = '.json'): string[] {
const baseDir = resolve(this.dir, directory);
const rootDir = resolve(this.dir);
if (!baseDir.startsWith(rootDir + sep) && baseDir !== rootDir) {
throw new Error(`Path traversal detected: directory "${directory}" escapes storage directory`);
}
if (!existsSync(baseDir)) return [];
if (!statSync(baseDir).isDirectory()) {
throw new Error(`Configured domain path "${directory}" is a file, expected a directory`);
}
return readdirSync(baseDir)
.filter(file => extname(file) === extension && statSync(join(baseDir, file)).isFile())
.map(file => `${directory}/${file}`);
}
/**
* Check whether a domain file currently exists on disk.
*/
domainFileExists(filename: string): boolean {
const filePath = resolve(this.dir, filename);
const rootDir = resolve(this.dir);
if (!filePath.startsWith(rootDir + sep) && filePath !== rootDir) {
throw new Error(`Path traversal detected: file "${filename}" escapes storage directory`);
}
return existsSync(filePath);
}View on GitHub (pinned to 75dd419e61)
Solutions
- Remove or rename the file at that path so the domain path can be a directory, or move its contents into a directory of that name.
- Fix the `directory` argument to point at an actual directory within storage.
- Inspect the storage root (`this.dir`) to see what occupies the path: `ls -la <root>/<directory>`.
- If migrating layouts, move legacy single-file data into the per-domain directory structure.
Example fix
// before
fs.writeFileSync(path.join(dir, 'workflows'), data); // file where dir expected
// after
fs.mkdirSync(path.join(dir, 'workflows'), { recursive: true });
fs.writeFileSync(path.join(dir, 'workflows', 'entry.json'), data); Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
function ensureDomainDir(base, dir) {
const p = require('path').join(base, dir);
if (fs.existsSync(p) && !fs.statSync(p).isDirectory()) {
throw new Error(`${p} is a file; expected a directory`);
}
} Try / catch
try {
return db.listDomainFiles(dir);
} catch (e) {
if (e.message.includes('is a file, expected a directory')) {
// surface a clear config/migration error to the operator
throw new Error(`Storage layout invalid at "${dir}": move or remove the file.`);
}
throw e;
} Prevention
- Check storage root layout after version/migration upgrades.
- Never write files to paths that double as domain directories.
- Add a startup check that each expected domain path is a directory.
- Keep editor/backup artifacts (e.g. workflows.json~, archive files) out of the storage root.
When it happens
Trigger: The configured domain path (e.g. `directory` argument or a storage dir layout) points at an existing file, so `readdirSync` would fail; listDomainFiles is called on a path where a file was placed where a directory is expected.
Common situations: A file (e.g. an accidental archive, editor artifact, or JSON written to the directory path) collides with a domain directory name; migrating storage layouts where old data was a single file; wrong `directory` argument naming a file.
Related errors
- ${this.name}: per-entity files directory is not configured
- AcpAgent does not support resuming suspended generate calls
- ACP prompt stopped before completing: ${response.stopReason}
- MastraAuthBetterAuth needs a database to build its own bette
- [Slack] Failed to resolve Mastra storage. Ensure your Mastra
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/eb3e3d817cd0b330.
Report an issue: GitHub.