mastra-ai/mastra · error
Tool must have input and output schemas defined
Error message
Tool must have input and output schemas defined
What it means
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.
Source
Thrown at packages/core/src/workflows/step-factories.ts:98
__agentOptions: agentOrToolOptions,
} as Step<TStepId, unknown, any, TStepOutput, unknown, unknown, DefaultEngineType>;
}
export function createStepFromTool<TStepInput, TSuspend, TResume, TStepOutput>(
params: ToolStep<TStepInput, TSuspend, TResume, TStepOutput, any>,
toolOpts?: {
retries?: number;
scorers?: DynamicArgument<MastraScorers>;
metadata?: StepMetadata;
/**
* Overrides the FGA actor for this tool call. Wins over a propagating run
* actor; pass `undefined` explicitly to drop back to user-actor resolution.
*/
actor?: ActorSignal;
},
): Step<string, any, TStepInput, TStepOutput, TResume, TSuspend, DefaultEngineType> {
if (!params.inputSchema || !params.outputSchema) {
throw new Error('Tool must have input and output schemas defined');
}
return {
id: params.id,
description: params.description,
inputSchema: params.inputSchema,
outputSchema: params.outputSchema,
resumeSchema: params.resumeSchema,
suspendSchema: params.suspendSchema,
retries: toolOpts?.retries,
scorers: toolOpts?.scorers,
metadata: toolOpts?.metadata,
// The run logic lives in `runToolEntry` (shared with the engines'
// declarative-entry dispatch); this closure just binds the live tool.
execute: async ctx =>
runToolEntry({ type: 'tool', id: params.id, toolId: params.id, tool: params, options: toolOpts }, ctx),
component: 'TOOL',
// Preserve the declarative inputs so the workflow builder can emit aView on GitHub (pinned to 75dd419e61)
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.
Example fix
// before
createStepFromTool({ id: 'myTool', execute: async (i) => i });
// after
import { z } from 'zod';
createStepFromTool({
id: 'myTool',
inputSchema: z.object({ q: z.string() }),
outputSchema: z.object({ answer: z.string() }),
execute: async ({ q }) => ({ answer: q.toUpperCase() }),
}); Defensive patterns
Strategy: validation
Validate before calling
function hasSchemas(tool: { inputSchema?: unknown; outputSchema?: unknown }) {
if (!tool.inputSchema || !tool.outputSchema) throw new Error('Tool must have input and output schemas defined');
} Type guard
function isSchemaComplete<T extends { inputSchema?: unknown; outputSchema?: unknown }>(t: T): t is T & { inputSchema: NonNullable<T['inputSchema']>; outputSchema: NonNullable<T['outputSchema']> } {
return t.inputSchema != null && t.outputSchema != null;
} Try / catch
try {
const step = createStepFromTool(tool);
} catch (e) {
if ((e as Error).message === 'Tool must have input and output schemas defined') {
console.error(`Tool '${tool.id}' is missing schemas`);
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- PROCESSOR_WORKFLOW_INVALID_OUTPUT
- Tool '${entry.toolId}' not found for workflow step '${entry.
- Invalid structured content for tool ${request.params.name}:
- expected an array of route segments
- @mastra/livekit: the agent requested tool approval or suspen
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/844a5263b60860f8.
Report an issue: GitHub.