mastra-ai/mastra · error · Error
Plugin instructions must be a string
Error message
Plugin instructions must be a string
What it means
resolvePluginInstructions accepts a plugin's `instructions` either as a static string or a function returning a string (possibly async). After resolving, if the resulting value is not a string, the loader throws 'Plugin instructions must be a string'. This catches plugins whose instructions function returns undefined, null, a number, a Promise that resolved to a non-string, or an object.
Source
Thrown at mastracode/sdk/src/plugins/loader.ts:293
throw new Error('Plugin processor lanes must be arrays');
}
for (const processor of [...input, ...output]) {
if (!processor || typeof processor !== 'object' || typeof processor.id !== 'string') {
throw new Error('Plugin processors must be objects with an id');
}
}
return { input, output };
}
async function resolvePluginInstructions(
plugin: MastraCodePlugin,
context: MastraCodePluginContext,
): Promise<string | undefined> {
if (plugin.instructions === undefined) return undefined;
const instructions =
typeof plugin.instructions === 'function' ? await plugin.instructions(context) : plugin.instructions;
if (typeof instructions !== 'string') {
throw new Error('Plugin instructions must be a string');
}
const trimmed = instructions.trim();
return trimmed.length > 0 ? trimmed : undefined;
}
function normalizePluginToolEntries(entries: MastraCodePluginToolEntries): {
tools: MastraCodePluginTools;
renderConfigs: Record<string, MastraCodeToolRenderConfig>;
} {
const tools: MastraCodePluginTools = {};
const renderConfigs: Record<string, MastraCodeToolRenderConfig> = {};
for (const [name, entry] of Object.entries(entries)) {
if (!isToolEntryObject(entry)) {
throw new Error(`Plugin tool "${name}" must be an object with a tool property`);
}
tools[name] = entry.tool;
if (entry.render) renderConfigs[name] = entry.render;
}View on GitHub (pinned to 75dd419e61)
Solutions
- Make the plugin's instructions a plain string, or ensure the instructions function always returns a string (call .trim() yourself and return '' if empty is intended).
- If the function can return undefined on some path, return an empty string instead so the loader treats it as 'no instructions'.
- If returning structured data, flatten it to a string (e.g. JSON.stringify or joining lines) before returning.
- Log/inspect the resolved value (typeof instructions) at the plugin boundary to find the offending return type.
Example fix
// before
instructions: async (ctx) => ({ text: `Mode: ${ctx.mode}` })
// after
instructions: async (ctx) => `Mode: ${ctx.mode}` Defensive patterns
Strategy: type-guard
Validate before calling
const resolved = typeof plugin.instructions === 'function' ? await plugin.instructions(ctx) : plugin.instructions;
if (resolved !== undefined && typeof resolved !== 'string') {
throw new TypeError(`Plugin ${plugin.name}: instructions must resolve to a string, got ${typeof resolved}`);
} Type guard
function isPluginInstructions(v: unknown): v is string | ((ctx: MastraCodePluginContext) => string | Promise<string>) {
return typeof v === 'string' || typeof v === 'function';
} Try / catch
try {
const instructions = await manager.instructions();
} catch (err) {
if (err instanceof Error && err.message === 'Plugin instructions must be a string') {
console.error('Plugin returned non-string instructions; check the instructions() return type');
} else throw err;
} Prevention
- Type plugin instructions as `string | ((ctx) => string | Promise<string>)` so TS rejects non-string returns at compile time.
- Never return undefined from the instructions callback — return '' to signal no instructions.
- Add a unit test asserting typeof resolved instructions === 'string' for every branch of the callback.
When it happens
Trigger: Calling instructions()/resolvePluginInstructions on a plugin where (a) `instructions` is set to a non-string non-function value, or (b) `instructions` is a function whose return/awaited result is not a string, e.g. `instructions: () => undefined`, `instructions: async () => ({ text: '...' })`, or `instructions: () => someNumber`.
Common situations: A plugin author returns an object like { body: '...' } from the instructions callback assuming structured instructions are supported; a function conditionally returns undefined on some branch; a refactor changed the return type from string to Promise<SummaryObject>; a config value typed as any leaks in as instructions.
Related errors
- Plugin tool "${name}" must be an object with a tool property
- mastra-wrapper plugin did not return code, there is likely a
- Plugin tool "${toolName}" is no longer available
- Plugin "${pluginId}" is not installed in ${scope} scope
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/cfe780bde24bfc0e.
Report an issue: GitHub.