mastra-ai/mastra · error
[FilesystemStorage] duplicate file path: ${file.path}
Error message
[FilesystemStorage] duplicate file path: ${file.path} What it means
validateFiles builds a Set of paths while iterating the supplied files; encountering the same path twice throws '[FilesystemStorage] duplicate file path: <path>'. Storage is keyed by path, so a batch containing duplicates is ambiguous and rejected wholesale.
Source
Thrown at mastracode/factory/src/storage/domains/filesystem/base.ts:67
!value ||
value.startsWith('/') ||
value.split('/').some(segment => !segment || segment === '.' || segment === '..')
) {
throw new Error('[FilesystemStorage] path must be a non-empty relative path.');
}
}
function assertScope(args: { resourceId: string; threadId: string }): void {
assertIdentifier(args.resourceId, 'resourceId');
assertIdentifier(args.threadId, 'threadId');
}
function validateFiles(files: FilesystemFile[]): void {
const paths = new Set<string>();
for (const file of files) {
assertRelativePath(file.path);
if (paths.has(file.path)) throw new Error(`[FilesystemStorage] duplicate file path: ${file.path}`);
paths.add(file.path);
}
}
export class FilesystemStorage extends FactoryStorageDomain {
constructor() {
super('filesystem');
}
async init(): Promise<void> {
await this.ensureCollections(FILESYSTEM_SCHEMAS);
}
async dangerouslyClearAll(): Promise<void> {
await this.ops.deleteMany(SNAPSHOTS, {});
}
async replaceFiles(input: ReplaceFilesystemFilesInput): Promise<void> {View on GitHub (pinned to 75dd419e61)
Solutions
- Deduplicate the array by path (keep the latest version) before calling replaceFiles
- Fix the merge logic so each path appears once per batch
- If intent is to append versions, use the appropriate upsert/single-file API instead of a duplicate batch
Example fix
// before
await storage.replaceFiles({ resourceId, threadId, files: [...existing, ...incoming] });
// after
const byPath = new Map([...existing, ...incoming].map(f => [f.path, f]));
await storage.replaceFiles({ resourceId, threadId, files: [...byPath.values()] }); Defensive patterns
Strategy: validation
Validate before calling
const deduped = [...new Map(files.map(f => [f.path, f])).values()];
if (deduped.length !== files.length) throw new Error('Duplicate paths in file batch'); Try / catch
try {
await storage.replaceFiles({ resourceId, threadId, files });
} catch (e) {
if (e instanceof Error && e.message.includes('duplicate file path')) {
logger.warn('Deduplicating file batch and retrying once');
await storage.replaceFiles({ resourceId, threadId, files: dedupeByPath(files) });
} else throw e;
} Prevention
- Dedupe by path whenever merging file batches from multiple sources
- Keep a single source of truth for file state instead of concatenating lists
- Add a lint/test asserting batch invariants before storage writes
- Prefer upsert APIs for repeated writes to the same path
When it happens
Trigger: Calling replaceFiles (which calls validateFiles) with a files array containing two FilesystemFile entries sharing the same path value.
Common situations: Merging uploads with existing state where the same file appears twice; deduplication lost after a refactor; batch built from multiple sources that can both include e.g. 'README.md'.
Related errors
- MastraFactory: duplicate integration id '${integration.id}'
- Missing required query param: ${label}
- ${label} must be relative
- ${label} escapes workspace
- Path escapes workspace
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/e38c97cc98cfac45.
Report an issue: GitHub.