mastra-ai/mastra · error · Error

Plugin entry must be inside the plugin directory

Error message

Plugin entry must be inside the plugin directory

What it means

detectEntry validates that an explicitly provided entry file resolves to a path inside the plugin directory. If the resolved entry escapes the plugin root (via `..` or an absolute path outside it), the SDK throws to prevent loading code from arbitrary locations.

Source

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

      const detectedEntry = tryDetectEntry(pluginDir);
      return detectedEntry ? [{ name: entry.name, path: pluginDir, entry: detectedEntry }] : [];
    });
}

function tryDetectEntry(pluginDir: string): string | undefined {
  try {
    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);
  }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Move the entry file inside the plugin directory and reference it relatively (e.g. `src/index.ts`).
  2. Remove `..` segments or absolute paths from the explicit entry setting.
  3. Omit the explicit entry and rely on auto-detection if the default candidates apply.
  4. If shared code is needed, publish/import it as a dependency rather than referencing it by path.

Example fix

// before
{ entry: '../shared/entry.ts' }

// after
{ entry: 'src/entry.ts' } // file lives inside the plugin dir
Defensive patterns

Strategy: validation

Validate before calling

import path from 'node:path';
export function entryIsInside(pluginDir: string, entry: string): boolean {
  const root = path.resolve(pluginDir);
  const resolved = path.resolve(pluginDir, entry);
  return resolved === root || resolved.startsWith(root + path.sep);
}
// call before install: entryIsInside(dir, entry) must be true

Prevention

When it happens

Trigger: Calling entry/detectEntry with an explicitEntry like `../shared/index.ts` or `/etc/something.ts` such that path.resolve(pluginDir, explicitEntry) fails the isInsideDirectory check against the resolved plugin dir.

Common situations: Config using `..` to reach shared code outside the plugin; passing an absolute path to a file in another repo; copying a config between projects where the entry now points outside the plugin dir.

Related errors


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