{"record":{"id":"cfc08147f4c1fb89","repo":"mastra-ai/mastra","slug":"plugin-manifest-file-plugin-at-index-index-m","errorCode":null,"errorMessage":"${PLUGIN_MANIFEST_FILE} plugin at index ${index} must be an object","messagePattern":"(.+?) plugin at index (.+?) must be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/plugins/manifest.ts","lineNumber":70,"sourceCode":"}\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`);\n  }\n  if (candidate.name !== undefined && typeof candidate.name !== 'string') {\n    throw new Error(`${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} name must be a string`);\n  }\n  return {\n    id: candidate.id,\n    entry: candidate.entry,\n    ...(candidate.name ? { name: candidate.name } : {}),\n  };\n}\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/plugins/manifest.ts#L52-L88","documentation":"validateManifestEntry() checks each entry of the `plugins` array in `.mastracode-plugin.json`. If an entry is null, an array, a string, or otherwise not a plain object, it throws this error with the entry's index so you can locate it in the file.","triggerScenarios":"A `.mastracode-plugin.json` whose plugins array contains a non-object element (e.g. a bare string id like `[\"my-plugin\"]`, `null` from a templating bug, or a nested array). Also triggered by upsertPluginManifestEntry when the entry argument passed in is not an object.","commonSituations":"Writing the manifest with code that stringifies ids instead of objects; merging manifests and flattening one level too far; copy-paste where an entry was mangled; JSON5/config generators emitting arrays of strings.","solutions":["Open `.mastracode-plugin.json`, go to the reported index in the plugins array, and replace the element with an object `{ \"id\": string, \"entry\": string }`.","If a script generates the manifest, fix it to push objects, not strings.","Validate the manifest shape (each element object with string id/entry) before running the plugin loader.","Regenerate the manifest via upsertPluginManifestEntry with a proper PluginManifestEntry object."],"exampleFix":"// before\n{ \"plugins\": [\"my-plugin\"] }\n// after\n{ \"plugins\": [{ \"id\": \"my-plugin\", \"entry\": \"./index.ts\" }] }","handlingStrategy":"type-guard","validationCode":"import fs from 'node:fs';\nconst m = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));\nfor (const [i, entry] of (m.plugins ?? []).entries()) {\n  if (!entry || typeof entry !== 'object' || typeof (entry as any).id !== 'string' || typeof (entry as any).entry !== 'string') {\n    throw new Error(`plugins[${i}] must be an object with string id and entry`);\n  }\n}","typeGuard":"function isManifestEntry(value: unknown): value is { id: string; entry: string; name?: string } {\n  if (!value || typeof value !== 'object') return false;\n  const e = value as Record<string, unknown>;\n  return typeof e.id === 'string' && e.id.length > 0 && typeof e.entry === 'string' && e.entry.length > 0;\n}","tryCatchPattern":"try {\n  const manifest = loadPluginManifest(rootDir);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('must be an object')) {\n    console.error('Bad manifest entry:', error.message);\n    return;\n  }\n  throw error;\n}","preventionTips":["Each plugins[] element must be an object with non-empty string `id` and `entry` — never a bare string.","Generate manifests via upsertPluginManifestEntry with typed PluginManifestEntry objects.","Run validateManifestEntry-style checks on generated manifests before committing.","Guard against null elements when merging or templating manifest files."],"tags":["manifest","schema-validation","type-mismatch","config"],"backgroundTag":"schema-validation-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}