mastra-ai/mastra · error · Error

Plugin entry must be a .ts file

Error message

Plugin entry must be a .ts file

What it means

detectEntry requires explicit plugin entry files to be TypeScript (`.ts`) since plugins are loaded from TS source. This throw fires when the explicit entry has a different extension (e.g. `.js`, `.mjs`, or no extension treated as a file).

Source

Thrown at mastracode/sdk/src/plugins/install.ts:163

    return detectEntry(pluginDir);
  } catch {
    return undefined;
  }
}

export function detectEntry(pluginDir: string, explicitEntry?: string): string {
  const root = path.resolve(pluginDir);
  if (explicitEntry) {
    const entryPath = path.resolve(pluginDir, explicitEntry);
    if (!isInsideDirectory(entryPath, root)) {
      throw new Error('Plugin entry must be inside the plugin directory');
    }
    if (fs.existsSync(entryPath) && fs.statSync(entryPath).isDirectory()) {
      const nestedEntry = detectEntry(entryPath);
      return path.relative(root, path.join(entryPath, nestedEntry));
    }
    if (path.extname(entryPath) !== '.ts') {
      throw new Error('Plugin entry must be a .ts file');
    }
    if (!fs.existsSync(entryPath) || !fs.statSync(entryPath).isFile()) {
      throw new Error(`Plugin entry file does not exist: ${explicitEntry}`);
    }
    return path.relative(root, entryPath);
  }

  const manifestPlugin = getSingleManifestPlugin(pluginDir);
  if (manifestPlugin) {
    return detectEntry(pluginDir, manifestPlugin.entry);
  }

  for (const candidate of ENTRY_CANDIDATES) {
    const entryPath = path.join(pluginDir, candidate);
    if (fs.existsSync(entryPath) && fs.statSync(entryPath).isFile()) {
      return candidate;
    }
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Point the entry at the TypeScript source file, e.g. `entry: 'src/index.ts'`.
  2. Rename/convert the entry to TypeScript if the plugin is authored in JS.
  3. Reference the `.ts` source, not a compiled `dist/*.js` output.

Example fix

// before
{ entry: 'dist/index.js' }

// after
{ entry: 'src/index.ts' }
Defensive patterns

Strategy: validation

Validate before calling

import path from 'node:path';
export function assertTsEntry(entry: string): void {
  if (path.extname(entry) !== '.ts') {
    throw new Error(`Plugin entry must be a .ts file, got: ${entry}`);
  }
}

Type guard

function isTsEntry(entry: string): boolean {
  return entry.endsWith('.ts') && !entry.endsWith('.d.ts');
}

Prevention

When it happens

Trigger: Calling entry/detectEntry with explicitEntry whose resolved path has path.extname !== '.ts' and is not a directory, e.g. `entry: 'index.js'` or `entry: 'main.mjs'`.

Common situations: Authors porting a JS plugin; pointing at a compiled `dist/index.js`; omitting the extension on a file that is not a `.ts` candidate.

Related errors


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