mastra-ai/mastra · error
${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} must include
Error message
${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} must include an entry What it means
Thrown by validateManifestEntry when a manifest entry has a valid `id` but its `entry` field is missing, not a string, or an empty string. The `entry` field points to the plugin's module path and is required for the plugin to be loaded; without it there is nothing to import, so the loader rejects the entry.
Source
Thrown at mastracode/sdk/src/plugins/manifest.ts:77
throw new Error(
`${PLUGIN_MANIFEST_FILE} contains multiple plugins. Provide an entry path for one of: ${manifest.plugins
.map(plugin => `${plugin.id} (${plugin.entry})`)
.join(', ')}`,
);
}
return manifest.plugins[0];
}
function validateManifestEntry(entry: unknown, index: number): PluginManifestEntry {
if (!entry || typeof entry !== 'object') {
throw new Error(`${PLUGIN_MANIFEST_FILE} plugin at index ${index} must be an object`);
}
const candidate = entry as { id?: unknown; name?: unknown; entry?: unknown };
if (typeof candidate.id !== 'string' || candidate.id.length === 0) {
throw new Error(`${PLUGIN_MANIFEST_FILE} plugin at index ${index} must include an id`);
}
if (typeof candidate.entry !== 'string' || candidate.entry.length === 0) {
throw new Error(`${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} must include an entry`);
}
if (candidate.name !== undefined && typeof candidate.name !== 'string') {
throw new Error(`${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} name must be a string`);
}
return {
id: candidate.id,
entry: candidate.entry,
...(candidate.name ? { name: candidate.name } : {}),
};
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Add a non-empty string `entry` to the manifest entry with the given id, pointing at the plugin's compiled module (e.g. "./dist/index.js").
- Confirm the referenced file actually exists relative to the manifest/package root and will exist at load time.
- If entry was lost during a build/generation step, fix the template or script so it always emits the entry path.
- Re-run the loader to validate.
Example fix
// before
{ "id": "my-plugin", "name": "My Plugin" }
// after
{ "id": "my-plugin", "name": "My Plugin", "entry": "./dist/index.js" } Defensive patterns
Strategy: validation
Validate before calling
const entries = JSON.parse(fs.readFileSync('plugins.json', 'utf8'));
for (const e of entries) {
if (typeof e?.entry !== 'string' || e.entry.length === 0) {
throw new Error(`plugin "${e?.id}" is missing its entry path; add it before loading`);
}
if (!fs.existsSync(path.join(pkgRoot, e.entry))) {
throw new Error(`entry path does not exist: ${e.entry}`);
}
} Type guard
function hasEntry(entry: unknown): entry is { id: string; entry: string } {
return typeof entry === 'object' && entry !== null &&
typeof (entry as { entry?: unknown }).entry === 'string' &&
(entry as { entry: string }).entry.length > 0;
} Try / catch
try {
loadPluginManifest(dir);
} catch (err) {
if (err instanceof Error && err.message.includes('must include an entry')) {
console.error(`Fix the manifest: ${err.message}`);
} else throw err;
} Prevention
- Generate manifest entries from a template that always fills in entry.
- Assert the built entry file exists (e.g. dist/index.js) as part of your build script.
- Keep build output paths stable so the entry path does not silently change.
When it happens
Trigger: loadPluginManifest reading a plugins.json entry like {"id":"my-plugin"} or {"id":"my-plugin","entry":""}; upsertPluginManifestEntry being called with an object lacking `entry`; a build step stripping the entry field.
Common situations: Creating a new manifest entry by copying only the id/name fields and forgetting entry; a template expansion that fails to substitute the entry path, leaving it empty; deleting the entry while reorganizing the project layout.
Related errors
- ${PLUGIN_MANIFEST_FILE} plugin at index ${index} must includ
- Google RBAC roleMapping is required.
- Cookie password must be at least 32 characters. Set OKTA_COO
- heartbeatMs must be a finite number no greater than ${MAX_TI
- Expected a PEM-encoded public key or certificate string for
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/f083758d206d532f.
Report an issue: GitHub.