mastra-ai/mastra · error · Error
${PLUGIN_MANIFEST_FILE} must contain a plugins array
Error message
${PLUGIN_MANIFEST_FILE} must contain a plugins array What it means
After successful JSON parsing, loadPluginManifest() requires the root object to have a `plugins` array. If the top level is not an object or `plugins` is missing/not an array, it throws this error. This catches manifests with the wrong shape rather than failing later with confusing undefined errors.
Source
Thrown at mastracode/sdk/src/plugins/manifest.ts:30
export type PluginManifest = {
plugins: PluginManifestEntry[];
};
export function loadPluginManifest(rootDir: string): PluginManifest | undefined {
const manifestPath = path.join(rootDir, PLUGIN_MANIFEST_FILE);
if (!fs.existsSync(manifestPath)) return undefined;
let parsed: unknown;
try {
parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
} catch (error) {
throw new Error(
`Could not parse ${PLUGIN_MANIFEST_FILE}: ${error instanceof Error ? error.message : String(error)}`,
);
}
if (!parsed || typeof parsed !== 'object' || !Array.isArray((parsed as { plugins?: unknown }).plugins)) {
throw new Error(`${PLUGIN_MANIFEST_FILE} must contain a plugins array`);
}
return {
plugins: (parsed as { plugins: unknown[] }).plugins.map((entry, index) => validateManifestEntry(entry, index)),
};
}
export function savePluginManifest(rootDir: string, manifest: PluginManifest): void {
fs.writeFileSync(path.join(rootDir, PLUGIN_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\n`);
}
export function upsertPluginManifestEntry(rootDir: string, entry: PluginManifestEntry): void {
const manifest = loadPluginManifest(rootDir) ?? { plugins: [] };
const validatedEntry = validateManifestEntry(entry, manifest.plugins.length);
const existingIndex = manifest.plugins.findIndex(plugin => plugin.id === validatedEntry.id);
if (existingIndex >= 0) {
manifest.plugins[existingIndex] = validateManifestEntry(validatedEntry, existingIndex);
} else {View on GitHub (pinned to 75dd419e61)
Solutions
- Make the top level an object with a `plugins` array: `{ "plugins": [ ... ] }`.
- Check the key spelling is exactly `plugins`.
- Regenerate the file programmatically via savePluginManifest to guarantee the correct shape.
- Diff against a known-good `.mastracode-plugin.json` from a working project.
Example fix
// before
[{ "id": "a", "entry": "./a.ts" }]
// after
{ "plugins": [{ "id": "a", "entry": "./a.ts" }] } Defensive patterns
Strategy: type-guard
Validate before calling
import fs from 'node:fs';
const parsed: unknown = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
if (!parsed || typeof parsed !== 'object' || !Array.isArray((parsed as { plugins?: unknown }).plugins)) {
throw new Error('.mastracode-plugin.json must be an object with a plugins array');
} Type guard
function isPluginManifest(value: unknown): value is { plugins: unknown[] } {
return (
!!value && typeof value === 'object' && Array.isArray((value as { plugins?: unknown }).plugins)
);
} Try / catch
try {
const manifest = loadPluginManifest(rootDir);
} catch (error) {
if (error instanceof Error && error.message.includes('must contain a plugins array')) {
console.error('Manifest shape wrong — expected { "plugins": [...] }');
return;
}
throw error;
} Prevention
- Use savePluginManifest to write manifests so the shape is guaranteed.
- Keep the schema `{ plugins: PluginManifestEntry[] }` in mind when authoring by hand.
- Watch for key typos: `plugin`, `plugins` plural exactly.
- Validate the parsed JSON against the expected top-level shape in CI.
When it happens
Trigger: `.mastracode-plugin.json` exists in rootDir, parses as valid JSON, but is e.g. a top-level array, `null`, `{}`, or has `"plugins": {...}` or a misspelled key like `"plugin": [...]`.
Common situations: Authoring the manifest from scratch with the wrong schema; confusing this file with another plugin config format; a tool rewriting the file with a different top-level structure; typos in the `plugins` key.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- ${PLUGIN_MANIFEST_FILE} plugin at index ${index} must be an
- expected an array of route segments
- Could not parse ${PLUGIN_MANIFEST_FILE}: ${error instanceof
- ${PLUGIN_MANIFEST_FILE} contains multiple plugins. Provide a
- Okta domain is required. Provide it in the options or set OK
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/c38c711c547aea81.
Report an issue: GitHub.