{"record":{"id":"cfe780bde24bfc0e","repo":"mastra-ai/mastra","slug":"plugin-instructions-must-be-a-string","errorCode":null,"errorMessage":"Plugin instructions must be a string","messagePattern":"Plugin instructions must be a string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/plugins/loader.ts","lineNumber":293,"sourceCode":"    throw new Error('Plugin processor lanes must be arrays');\n  }\n  for (const processor of [...input, ...output]) {\n    if (!processor || typeof processor !== 'object' || typeof processor.id !== 'string') {\n      throw new Error('Plugin processors must be objects with an id');\n    }\n  }\n  return { input, output };\n}\n\nasync function resolvePluginInstructions(\n  plugin: MastraCodePlugin,\n  context: MastraCodePluginContext,\n): Promise<string | undefined> {\n  if (plugin.instructions === undefined) return undefined;\n  const instructions =\n    typeof plugin.instructions === 'function' ? await plugin.instructions(context) : plugin.instructions;\n  if (typeof instructions !== 'string') {\n    throw new Error('Plugin instructions must be a string');\n  }\n  const trimmed = instructions.trim();\n  return trimmed.length > 0 ? trimmed : undefined;\n}\n\nfunction normalizePluginToolEntries(entries: MastraCodePluginToolEntries): {\n  tools: MastraCodePluginTools;\n  renderConfigs: Record<string, MastraCodeToolRenderConfig>;\n} {\n  const tools: MastraCodePluginTools = {};\n  const renderConfigs: Record<string, MastraCodeToolRenderConfig> = {};\n  for (const [name, entry] of Object.entries(entries)) {\n    if (!isToolEntryObject(entry)) {\n      throw new Error(`Plugin tool \"${name}\" must be an object with a tool property`);\n    }\n    tools[name] = entry.tool;\n    if (entry.render) renderConfigs[name] = entry.render;\n  }","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/plugins/loader.ts#L275-L311","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"// before\ninstructions: async (ctx) => ({ text: `Mode: ${ctx.mode}` })\n// after\ninstructions: async (ctx) => `Mode: ${ctx.mode}`","handlingStrategy":"type-guard","validationCode":"const resolved = typeof plugin.instructions === 'function' ? await plugin.instructions(ctx) : plugin.instructions;\nif (resolved !== undefined && typeof resolved !== 'string') {\n  throw new TypeError(`Plugin ${plugin.name}: instructions must resolve to a string, got ${typeof resolved}`);\n}","typeGuard":"function isPluginInstructions(v: unknown): v is string | ((ctx: MastraCodePluginContext) => string | Promise<string>) {\n  return typeof v === 'string' || typeof v === 'function';\n}","tryCatchPattern":"try {\n  const instructions = await manager.instructions();\n} catch (err) {\n  if (err instanceof Error && err.message === 'Plugin instructions must be a string') {\n    console.error('Plugin returned non-string instructions; check the instructions() return type');\n  } else throw err;\n}","preventionTips":["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."],"tags":["plugin","type-validation","sdk"],"backgroundTag":"plugin-instructions-type-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}