{"record":{"id":"c38c711c547aea81","repo":"mastra-ai/mastra","slug":"plugin-manifest-file-must-contain-a-plugins-arr","errorCode":null,"errorMessage":"${PLUGIN_MANIFEST_FILE} must contain a plugins array","messagePattern":"(.+?) must contain a plugins array","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/plugins/manifest.ts","lineNumber":30,"sourceCode":"export type PluginManifest = {\n  plugins: PluginManifestEntry[];\n};\n\nexport function loadPluginManifest(rootDir: string): PluginManifest | undefined {\n  const manifestPath = path.join(rootDir, PLUGIN_MANIFEST_FILE);\n  if (!fs.existsSync(manifestPath)) return undefined;\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\n  } catch (error) {\n    throw new Error(\n      `Could not parse ${PLUGIN_MANIFEST_FILE}: ${error instanceof Error ? error.message : String(error)}`,\n    );\n  }\n\n  if (!parsed || typeof parsed !== 'object' || !Array.isArray((parsed as { plugins?: unknown }).plugins)) {\n    throw new Error(`${PLUGIN_MANIFEST_FILE} must contain a plugins array`);\n  }\n\n  return {\n    plugins: (parsed as { plugins: unknown[] }).plugins.map((entry, index) => validateManifestEntry(entry, index)),\n  };\n}\n\nexport function savePluginManifest(rootDir: string, manifest: PluginManifest): void {\n  fs.writeFileSync(path.join(rootDir, PLUGIN_MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}\\n`);\n}\n\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 {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/plugins/manifest.ts#L12-L48","documentation":"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.","triggerScenarios":"`.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\": [...]`.","commonSituations":"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.","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."],"exampleFix":"// before\n[{ \"id\": \"a\", \"entry\": \"./a.ts\" }]\n// after\n{ \"plugins\": [{ \"id\": \"a\", \"entry\": \"./a.ts\" }] }","handlingStrategy":"type-guard","validationCode":"import fs from 'node:fs';\nconst parsed: unknown = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\nif (!parsed || typeof parsed !== 'object' || !Array.isArray((parsed as { plugins?: unknown }).plugins)) {\n  throw new Error('.mastracode-plugin.json must be an object with a plugins array');\n}","typeGuard":"function isPluginManifest(value: unknown): value is { plugins: unknown[] } {\n  return (\n    !!value && typeof value === 'object' && Array.isArray((value as { plugins?: unknown }).plugins)\n  );\n}","tryCatchPattern":"try {\n  const manifest = loadPluginManifest(rootDir);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('must contain a plugins array')) {\n    console.error('Manifest shape wrong — expected { \"plugins\": [...] }');\n    return;\n  }\n  throw error;\n}","preventionTips":["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."],"tags":["manifest","schema-validation","config","shape-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}