mastra-ai/mastra · error · Error

Unsupported plugin entry extension "${path.extname(entryPath

Error message

Unsupported plugin entry extension "${path.extname(entryPath)}". V1 plugins must use .ts entries.

What it means

importPluginModule only accepts .ts entry files in V1: the SDK relies on its TS-aware import pipeline (with mtime/size cache-busting) which is wired for TypeScript entries. Any other extension (.js, .mjs, .cjs, .json) is rejected before import.

Source

Thrown at mastracode/sdk/src/plugins/loader.ts:155

}

export function isInsideDirectory(targetPath: string, root: string): boolean {
  const resolvedTarget = path.resolve(targetPath);
  const resolvedRoot = path.resolve(root);
  return resolvedTarget === resolvedRoot || resolvedTarget.startsWith(resolvedRoot + path.sep);
}

function resolveExistingAssetDirs(pluginRoot: string, dirname: 'skills' | 'commands'): string[] {
  const dir = path.join(pluginRoot, dirname);
  try {
    return fs.statSync(dir).isDirectory() ? [dir] : [];
  } catch {
    return [];
  }
}

async function importPluginModule(entryPath: string): Promise<MastraCodePlugin> {
  if (path.extname(entryPath) !== '.ts') {
    throw new Error(
      `Unsupported plugin entry extension "${path.extname(entryPath)}". V1 plugins must use .ts entries.`,
    );
  }

  const url = pathToFileURL(entryPath);
  const stat = fs.statSync(entryPath, { bigint: true });
  url.searchParams.set('mtimeNs', stat.mtimeNs.toString());
  url.searchParams.set('size', stat.size.toString());
  const mod = (await import(url.href)) as { default?: unknown; plugin?: unknown };
  return validatePluginExport(mod.default ?? mod.plugin);
}

function validatePluginExport(value: unknown): MastraCodePlugin {
  if (!value || typeof value !== 'object') {
    throw new Error('Plugin module must export a plugin object as default or named "plugin" export');
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Point record.entry at the plugin's TypeScript source file, e.g. 'src/index.ts'.
  2. Rename the entry to .ts and convert the module to TypeScript (the loader imports TS directly).
  3. Update the stale plugins.json entry if it still references an old .js build output.

Example fix

// before (plugins.json)
{ "id": "widgets", "entry": "dist/index.js", ... }
// after
{ "id": "widgets", "entry": "src/index.ts", ... }
Defensive patterns

Strategy: validation

Validate before calling

import path from 'node:path';
function isTsEntry(entry: string): boolean {
  return path.extname(entry) === '.ts';
}
if (!isTsEntry(record.entry)) throw new Error(`V1 plugins require a .ts entry, got "${record.entry}"`);

Try / catch

const loaded = await loadPluginRecord(record, options);
if (loaded.status === 'load failed' && loaded.error?.includes('Unsupported plugin entry extension')) {
  console.error(`Point record.entry at the .ts source (e.g. src/index.ts), not a JS build output.`);
}

Prevention

When it happens

Trigger: record.entry pointing at 'dist/plugin.js' or 'index.mjs' (e.g. after building the plugin or porting to JS); a JSON entry; a plugin package that ships only compiled JS.

Common situations: Migrating an existing JS plugin package into mastracode; pointing the entry at a build output directory out of habit from npm-package conventions; typos giving the file a wrong extension.

Related errors


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