{"record":{"id":"2ec8e7dba1575c81","repo":"mastra-ai/mastra","slug":"plugin-manifest-file-contains-multiple-plugins","errorCode":null,"errorMessage":"${PLUGIN_MANIFEST_FILE} contains multiple plugins. Provide an entry path for one of: ${manifest.plugins.map(plugin => `${plugin.id} (${plugin.entry})`).join(', ')}","messagePattern":"(.+?) contains multiple plugins\\. Provide an entry path for one of: (.+?) \\((.+?)\\)`\\)\\.join\\(', '\\)\\}","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/plugins/manifest.ts","lineNumber":59,"sourceCode":"\nexport function upsertPluginManifestEntry(rootDir: string, entry: PluginManifestEntry): void {\n  const manifest = loadPluginManifest(rootDir) ?? { plugins: [] };\n  const validatedEntry = validateManifestEntry(entry, manifest.plugins.length);\n  const existingIndex = manifest.plugins.findIndex(plugin => plugin.id === validatedEntry.id);\n  if (existingIndex >= 0) {\n    manifest.plugins[existingIndex] = validateManifestEntry(validatedEntry, existingIndex);\n  } else {\n    manifest.plugins.push(validatedEntry);\n  }\n  savePluginManifest(rootDir, manifest);\n}\n\nexport function getSingleManifestPlugin(rootDir: string): PluginManifestEntry | undefined {\n  const manifest = loadPluginManifest(rootDir);\n  if (!manifest) return undefined;\n  if (manifest.plugins.length === 0) return undefined;\n  if (manifest.plugins.length > 1) {\n    throw new Error(\n      `${PLUGIN_MANIFEST_FILE} contains multiple plugins. Provide an entry path for one of: ${manifest.plugins\n        .map(plugin => `${plugin.id} (${plugin.entry})`)\n        .join(', ')}`,\n    );\n  }\n  return manifest.plugins[0];\n}\n\nfunction validateManifestEntry(entry: unknown, index: number): PluginManifestEntry {\n  if (!entry || typeof entry !== 'object') {\n    throw new Error(`${PLUGIN_MANIFEST_FILE} plugin at index ${index} must be an object`);\n  }\n  const candidate = entry as { id?: unknown; name?: unknown; entry?: unknown };\n  if (typeof candidate.id !== 'string' || candidate.id.length === 0) {\n    throw new Error(`${PLUGIN_MANIFEST_FILE} plugin at index ${index} must include an id`);\n  }\n  if (typeof candidate.entry !== 'string' || candidate.entry.length === 0) {\n    throw new Error(`${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} must include an entry`);","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/plugins/manifest.ts#L41-L77","documentation":"getSingleManifestPlugin() resolves the one plugin described by `.mastracode-plugin.json` when no explicit entry path is given. If the manifest declares more than one plugin, no single default can be chosen, so it throws and lists each plugin's id and entry so you can specify one.","triggerScenarios":"Calling getSingleManifestPlugin (via manifestPlugin) against a rootDir whose manifest contains 2+ entries, without passing an entry path/selector for one of them.","commonSituations":"Adding a second plugin to a shared manifest and forgetting that the manifest-plugin loader expects exactly one; multi-plugin monorepo where the build tooling used to auto-pick the single entry; leftover entries from copied manifests.","solutions":["Pass an explicit entry path / select the desired plugin at the manifestPlugin call site instead of relying on single-plugin inference.","Reduce the manifest to one plugin if only one is intended; remove stale entries.","Split plugins into separate directories, each with its own `.mastracode-plugin.json` containing one entry.","Pick from the ids listed in the error message — it enumerates `id (entry)` for every plugin."],"exampleFix":"// before\nmanifestPlugin(rootDir)\n// after — point at one entry explicitly\nmanifestPlugin(rootDir, { entry: './plugins/beta.ts' })","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nconst m = JSON.parse(fs.readFileSync(path.join(rootDir, '.mastracode-plugin.json'), 'utf8'));\nif (Array.isArray(m.plugins) && m.plugins.length > 1) {\n  // pass an explicit entry to manifestPlugin instead of relying on the single-plugin path\n  console.warn('Multiple plugins:', m.plugins.map((p: any) => p.id));\n}","typeGuard":"function hasSinglePlugin(manifest: { plugins: unknown[] }): manifest is { plugins: [unknown] } {\n  return manifest.plugins.length === 1;\n}","tryCatchPattern":"try {\n  const plugin = getSingleManifestPlugin(rootDir);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('contains multiple plugins')) {\n    console.error('Specify an entry path; candidates:', error.message);\n    return;\n  }\n  throw error;\n}","preventionTips":["Only rely on getSingleManifestPlugin when the manifest is guaranteed to hold one entry.","Pass an explicit entry path to manifestPlugin for multi-plugin manifests.","Clean stale plugin entries out of shared manifests.","Keep one manifest per plugin directory if you use single-plugin inference."],"tags":["manifest","ambiguity","multiple-plugins","config"],"backgroundTag":"ambiguous-plugin-manifest","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}