mastra-ai/mastra · error · Error

${PLUGIN_MANIFEST_FILE} plugin at index ${index} must be an

Error message

${PLUGIN_MANIFEST_FILE} plugin at index ${index} must be an object

What it means

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.

Source

Thrown at mastracode/sdk/src/plugins/manifest.ts:70

}

export function getSingleManifestPlugin(rootDir: string): PluginManifestEntry | undefined {
  const manifest = loadPluginManifest(rootDir);
  if (!manifest) return undefined;
  if (manifest.plugins.length === 0) return undefined;
  if (manifest.plugins.length > 1) {
    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

  1. Open `.mastracode-plugin.json`, go to the reported index in the plugins array, and replace the element with an object `{ "id": string, "entry": string }`.
  2. If a script generates the manifest, fix it to push objects, not strings.
  3. Validate the manifest shape (each element object with string id/entry) before running the plugin loader.
  4. Regenerate the manifest via upsertPluginManifestEntry with a proper PluginManifestEntry object.

Example fix

// before
{ "plugins": ["my-plugin"] }
// after
{ "plugins": [{ "id": "my-plugin", "entry": "./index.ts" }] }
Defensive patterns

Strategy: type-guard

Validate before calling

import fs from 'node:fs';
const m = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
for (const [i, entry] of (m.plugins ?? []).entries()) {
  if (!entry || typeof entry !== 'object' || typeof (entry as any).id !== 'string' || typeof (entry as any).entry !== 'string') {
    throw new Error(`plugins[${i}] must be an object with string id and entry`);
  }
}

Type guard

function isManifestEntry(value: unknown): value is { id: string; entry: string; name?: string } {
  if (!value || typeof value !== 'object') return false;
  const e = value as Record<string, unknown>;
  return typeof e.id === 'string' && e.id.length > 0 && typeof e.entry === 'string' && e.entry.length > 0;
}

Try / catch

try {
  const manifest = loadPluginManifest(rootDir);
} catch (error) {
  if (error instanceof Error && error.message.includes('must be an object')) {
    console.error('Bad manifest entry:', error.message);
    return;
  }
  throw error;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/cfc08147f4c1fb89. Report an issue: GitHub.