mastra-ai/mastra · error

[FilesystemStorage] resourceId must not be empty.

Error message

[FilesystemStorage] resourceId must not be empty.

What it means

FilesystemStorage's assertIdentifier rejects empty/whitespace identifiers. When assertScope validates a call's resourceId and finds it empty, it throws '[FilesystemStorage] resourceId must not be empty.' resourceId is the primary partition key for stored files, so the domain refuses to proceed.

Source

Thrown at mastracode/factory/src/storage/domains/filesystem/base.ts:44

    uniqueIndexes: [
      {
        name: 'filesystem_snapshots_resource_thread_unique',
        columns: ['resource_id', 'thread_id'],
      },
    ],
  },
];

interface FilesystemSnapshotDbRow extends Record<string, unknown> {
  id: string;
  resource_id: string;
  thread_id: string;
  files: FilesystemFile[];
  captured_at: Date;
}

function assertIdentifier(value: string, label: string): void {
  if (!value.trim()) throw new Error(`[FilesystemStorage] ${label} must not be empty.`);
}

function assertRelativePath(value: string): void {
  if (
    !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 {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass a non-empty resourceId string to the storage call
  2. Validate the resourceId at the API boundary before calling storage
  3. Fix field naming/spread so the resource ID actually reaches args.resourceId
  4. Trim user input and reject blanks early

Example fix

// before
await storage.list({ resourceId: input.resourceId ?? '', threadId });
// after
if (!input.resourceId?.trim()) throw new ValidationError('resourceId is required');
await storage.list({ resourceId: input.resourceId, threadId });
Defensive patterns

Strategy: validation

Validate before calling

function requireResourceId(v: string | undefined): string {
  const id = (v ?? '').trim();
  if (!id) throw new Error('resourceId is required and must not be blank');
  return id;
}

Type guard

function hasResourceId(args: { resourceId?: string; threadId: string }): args is { resourceId: string; threadId: string } {
  return typeof args.resourceId === 'string' && args.resourceId.trim().length > 0;
}

Try / catch

try {
  await storage.call(args);
} catch (e) {
  if (e instanceof Error && e.message === '[FilesystemStorage] resourceId must not be empty.') {
    throw new BadRequest('resourceId is required');
  }
  throw e;
}

Prevention

When it happens

Trigger: Any FilesystemStorage domain method that runs assertScope with args.resourceId set to '' or whitespace — e.g. listing/saving files without supplying the resource ID.

Common situations: Caller built the args object conditionally and omitted resourceId; an upstream object spread produced undefined coerced in as empty; refactoring renamed the field so the value no longer lands in resourceId.

Related errors


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