{"record":{"id":"844a5263b60860f8","repo":"mastra-ai/mastra","slug":"tool-must-have-input-and-output-schemas-defined-844a52","errorCode":null,"errorMessage":"Tool must have input and output schemas defined","messagePattern":"Tool must have input and output schemas defined","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/step-factories.ts","lineNumber":98,"sourceCode":"    __agentOptions: agentOrToolOptions,\n  } as Step<TStepId, unknown, any, TStepOutput, unknown, unknown, DefaultEngineType>;\n}\n\nexport function createStepFromTool<TStepInput, TSuspend, TResume, TStepOutput>(\n  params: ToolStep<TStepInput, TSuspend, TResume, TStepOutput, any>,\n  toolOpts?: {\n    retries?: number;\n    scorers?: DynamicArgument<MastraScorers>;\n    metadata?: StepMetadata;\n    /**\n     * Overrides the FGA actor for this tool call. Wins over a propagating run\n     * actor; pass `undefined` explicitly to drop back to user-actor resolution.\n     */\n    actor?: ActorSignal;\n  },\n): Step<string, any, TStepInput, TStepOutput, TResume, TSuspend, DefaultEngineType> {\n  if (!params.inputSchema || !params.outputSchema) {\n    throw new Error('Tool must have input and output schemas defined');\n  }\n\n  return {\n    id: params.id,\n    description: params.description,\n    inputSchema: params.inputSchema,\n    outputSchema: params.outputSchema,\n    resumeSchema: params.resumeSchema,\n    suspendSchema: params.suspendSchema,\n    retries: toolOpts?.retries,\n    scorers: toolOpts?.scorers,\n    metadata: toolOpts?.metadata,\n    // The run logic lives in `runToolEntry` (shared with the engines'\n    // declarative-entry dispatch); this closure just binds the live tool.\n    execute: async ctx =>\n      runToolEntry({ type: 'tool', id: params.id, toolId: params.id, tool: params, options: toolOpts }, ctx),\n    component: 'TOOL',\n    // Preserve the declarative inputs so the workflow builder can emit a","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/step-factories.ts#L80-L116","documentation":"createStepFromTool requires the tool params to carry both inputSchema and outputSchema; if either is missing it throws. Schemas are needed to type and validate data flowing into and out of the tool-as-step.","triggerScenarios":"Calling createStepFromTool (or createStep/tool helpers that route to it) with a tool object lacking inputSchema or outputSchema — e.g. a hand-built tool object, a tool imported from code that defines only one schema, or a dynamically constructed tool where schemas were added conditionally.","commonSituations":"Tools built programmatically where one schema was forgotten; migrating tools from an API that made schemas optional; tools deserialized from storage without their schema metadata.","solutions":["Define both inputSchema and outputSchema on the tool before passing it to createStepFromTool.","Check the tool factory/constructor used to build the tool and ensure it emits both schemas.","If a schema is genuinely unused, supply an explicit trivial schema (e.g. z.object({})).","Type the tool with the library's Tool type so missing schemas are a compile-time error."],"exampleFix":"// before\ncreateStepFromTool({ id: 'myTool', execute: async (i) => i });\n// after\nimport { z } from 'zod';\ncreateStepFromTool({\n  id: 'myTool',\n  inputSchema: z.object({ q: z.string() }),\n  outputSchema: z.object({ answer: z.string() }),\n  execute: async ({ q }) => ({ answer: q.toUpperCase() }),\n});","handlingStrategy":"validation","validationCode":"function hasSchemas(tool: { inputSchema?: unknown; outputSchema?: unknown }) {\n  if (!tool.inputSchema || !tool.outputSchema) throw new Error('Tool must have input and output schemas defined');\n}","typeGuard":"function isSchemaComplete<T extends { inputSchema?: unknown; outputSchema?: unknown }>(t: T): t is T & { inputSchema: NonNullable<T['inputSchema']>; outputSchema: NonNullable<T['outputSchema']> } {\n  return t.inputSchema != null && t.outputSchema != null;\n}","tryCatchPattern":"try {\n  const step = createStepFromTool(tool);\n} catch (e) {\n  if ((e as Error).message === 'Tool must have input and output schemas defined') {\n    console.error(`Tool '${tool.id}' is missing schemas`);\n  } else throw e;\n}","preventionTips":["Always define inputSchema and outputSchema when constructing tools","Use z.object({}) for tools that take or return no data","Type tools with the library's Tool type so gaps surface at compile time","Add a test per tool asserting both schemas exist"],"tags":["workflows","tools","schema-validation","step-factory"],"backgroundTag":"missing-schema-definition","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}