mastra-ai/mastra · error

${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} name must be

Error message

${PLUGIN_MANIFEST_FILE} plugin ${candidate.id} name must be a string

What it means

Thrown by validateManifestEntry when a manifest entry supplies a `name` that is not a string. The `name` field is optional (it is only spread into the result when truthy), but if present it must be a string, since it is used as a human-readable display name. The library fails fast instead of coercing or ignoring bad values.

Source

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

        .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. Change the entry's `name` value to a quoted string (e.g. "name": "My Plugin").
  2. If no display name is needed, remove the `name` key entirely — it is optional.
  3. Fix any config-generation code that emits non-string names (numbers, booleans, null).
  4. Re-run to confirm the manifest passes validation.

Example fix

// before
{ "id": "my-plugin", "entry": "./dist/index.js", "name": 42 }
// after
{ "id": "my-plugin", "entry": "./dist/index.js", "name": "42" }
Defensive patterns

Strategy: type-guard

Validate before calling

const entries = JSON.parse(fs.readFileSync('plugins.json', 'utf8'));
const bad = entries.filter(e => 'name' in e && typeof e.name !== 'string');
if (bad.length) throw new Error(`non-string name in manifest for: ${bad.map(e => e.id).join(', ')}`);

Type guard

function hasValidName(entry: { name?: unknown }): entry is { name?: string } {
  return entry.name === undefined || typeof entry.name === 'string';
}

Try / catch

try {
  loadPluginManifest(dir);
} catch (err) {
  if (err instanceof Error && err.message.includes('name must be a string')) {
    console.error(`Manifest name field has wrong type: ${err.message}`);
  } else throw err;
}

Prevention

When it happens

Trigger: loadPluginManifest encountering an entry like {"id":"x","entry":"./dist/index.js","name":123} or name:true; upsertPluginManifestEntry being handed an object with a numeric or null name.

Common situations: JSON tooling or a config generator emitting a numeric version-like name (e.g. name: 2); hand-editing and leaving name: null or name: true; importing manifest data from another tool that uses a different name type.

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/ad386a8fdbfebe1c. Report an issue: GitHub.