mastra-ai/mastra · error · Error
Plugin at ${pluginRoot} must declare an exact pnpm version i
Error message
Plugin at ${pluginRoot} must declare an exact pnpm version in package.json using "packageManager": "pnpm@x.y.z". What it means
getPnpmVersion requires the plugin's package.json to pin an exact pnpm version via the `packageManager` field. This throw fires when the field is missing or is not a string. The exact version is needed so dependency installation is reproducible across machines.
Source
Thrown at mastracode/sdk/src/plugins/dependencies.ts:104
while (isInsideDirectory(current, root)) {
if (fs.existsSync(path.join(current, 'package.json'))) {
return current;
}
if (current === root) break;
current = path.dirname(current);
}
return undefined;
}
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 getPnpmVersion(pluginRoot: string, packageManager: unknown): string {
if (typeof packageManager !== 'string') {
throw new Error(
`Plugin at ${pluginRoot} must declare an exact pnpm version in package.json using "packageManager": "pnpm@x.y.z".`,
);
}
const match = /^pnpm@(\d+\.\d+\.\d+)$/.exec(packageManager);
if (!match?.[1]) {
throw new Error(
`Plugin at ${pluginRoot} must declare an exact pnpm version in package.json using "packageManager": "pnpm@x.y.z".`,
);
}
return match[1];
}
function getInstallCommand(pluginRoot: string, pnpmVersion: string): InstallCommand {
const installArgs = ['install', '--ignore-workspace'];
if (hasFile(pluginRoot, 'pnpm-lock.yaml')) installArgs.push('--frozen-lockfile');
installArgs.push('--ignore-scripts');View on GitHub (pinned to 75dd419e61)
Solutions
- Add `"packageManager": "pnpm@<exact-version>"` (e.g. `pnpm@9.12.0`) to the plugin's package.json.
- Run `corepack use pnpm@latest` in the plugin directory to set the field automatically.
- Commit the updated package.json and reinstall the plugin.
Example fix
// before: plugin package.json
{
"name": "my-plugin"
}
// after
{
"name": "my-plugin",
"packageManager": "pnpm@9.12.0"
} Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
export function assertPinnedPnpm(pluginRoot: string): void {
const pkg = JSON.parse(fs.readFileSync(`${pluginRoot}/package.json`, 'utf8'));
const pm = pkg.packageManager;
if (typeof pm !== 'string' || !/^pnpm@\d+\.\d+\.\d+$/.test(pm)) {
throw new Error(`${pluginRoot}: add "packageManager": "pnpm@x.y.z" to package.json`);
}
} Type guard
function isPinnedPnpm(v: unknown): v is `pnpm@${number}.${number}.${number}` {
return typeof v === 'string' && /^pnpm@\d+\.\d+\.\d+$/.test(v);
} Prevention
- Always initialize plugins with `corepack use pnpm@<version>` so the field is written for you.
- Add a lint/CI check asserting packageManager matches /^pnpm@\d+\.\d+\.\d+$/.t
- Never hand-edit or strip the packageManager field in publish scripts.
When it happens
Trigger: Calling pnpmVersion (via getPnpmVersion) for a plugin whose package.json either has no `packageManager` key or whose value is not a string (e.g. null after JSON parse, or a non-string value).
Common situations: Plugin authors forgot to add `packageManager`; the field was stripped by a publish step; hand-edited package.json with a malformed value.
Related errors
- Plugin entry must be inside the plugin directory
- Plugin entry must be a .ts file
- Plugin entry file does not exist: ${explicitEntry}
- Could not find a plugin entry file. Tried: ${ENTRY_CANDIDATE
- Could not determine project name from package.json. Use --pr
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/840bf8f3429243f3.
Report an issue: GitHub.