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

  1. Deduplicate the array by path (keep the latest version) before calling replaceFiles
  2. Fix the merge logic so each path appears once per batch
  3. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/e38c97cc98cfac45. Report an issue: GitHub.