mastra-ai/mastra · error

Cannot create workflow definition "${input.id}": inputSchema

Error message

Cannot create workflow definition "${input.id}": inputSchema, outputSchema, and graph are required.

What it means

`upsert` in the workflow-definitions storage requires a definition record to carry non-undefined `inputSchema`, `outputSchema`, and `graph` fields. If any is missing or explicitly undefined, it refuses to persist the definition, since these three fields define the workflow contract and executable structure.

Source

Thrown at packages/core/src/storage/domains/workflow-definitions/inmemory.ts:56

        ...('status' in input && input.status !== undefined && { status: input.status }),
        ...('authorId' in input && input.authorId !== undefined && { authorId: input.authorId }),
        updatedAt: now,
      };
      this.db.workflowDefinitions.set(input.id, merged);
      return this.deepCopy(merged);
    }

    // Creation requires the full schema set + graph. Check values, not key
    // presence — `{ graph: undefined }` must not slip through.
    if (
      !('inputSchema' in input) ||
      input.inputSchema === undefined ||
      !('outputSchema' in input) ||
      input.outputSchema === undefined ||
      !('graph' in input) ||
      input.graph === undefined
    ) {
      throw new Error(
        `Cannot create workflow definition "${input.id}": inputSchema, outputSchema, and graph are required.`,
      );
    }

    const def: WorkflowDefinition = {
      id: input.id,
      description: input.description,
      metadata: input.metadata,
      inputSchema: input.inputSchema,
      outputSchema: input.outputSchema,
      stateSchema: input.stateSchema,
      requestContextSchema: input.requestContextSchema,
      graph: input.graph,
      status: 'active',
      source: 'storage',
      authorId: 'authorId' in input ? input.authorId : undefined,
      createdAt: now,
      updatedAt: now,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Provide all three fields: derive `inputSchema`/`outputSchema` from the workflow (e.g. zod `.jsonSchema()` or zod-to-json-schema) and `graph` from the serialized workflow graph.
  2. If updating an existing definition, load it first and merge the existing schemas/graph instead of upserting a partial record.
  3. Validate the input payload shape before calling upsert.
  4. Fix serialization so `undefined` fields are not stripped or turned into explicit undefined values.

Example fix

// before
await wfStorage.upsert({ id: 'wf-1', name: 'My flow' });
// after
await wfStorage.upsert({
  id: 'wf-1',
  name: 'My flow',
  inputSchema: z.object({}).jsonSchema(),
  outputSchema: z.object({}).jsonSchema(),
  graph: serializedGraph,
});
Defensive patterns

Strategy: validation

Validate before calling

function assertWorkflowDefinitionInput(input: { id: string; inputSchema?: unknown; outputSchema?: unknown; graph?: unknown }) {
  const missing: string[] = [];
  if (input.inputSchema === undefined) missing.push('inputSchema');
  if (input.outputSchema === undefined) missing.push('outputSchema');
  if (input.graph === undefined) missing.push('graph');
  if (missing.length) throw new Error(`Workflow definition "${input.id}" missing: ${missing.join(', ')}`);
}

Type guard

function isCompleteWorkflowDefinition(
  input: Partial<{ inputSchema: unknown; outputSchema: unknown; graph: unknown }>,
): input is { inputSchema: unknown; outputSchema: unknown; graph: unknown } {
  return 'inputSchema' in input && input.inputSchema !== undefined
    && 'outputSchema' in input && input.outputSchema !== undefined
    && 'graph' in input && input.graph !== undefined;
}

Try / catch

try {
  await wfStorage.upsert(input);
} catch (err) {
  if (err instanceof Error && err.message.includes('inputSchema, outputSchema, and graph are required')) {
    const existing = await wfStorage.getDefinition(input.id); // merge missing fields
    await wfStorage.upsert({ ...existing, ...input });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling `upsert({ id, name, description })` (or via `updated`) with a partial input lacking `inputSchema`/`outputSchema`/`graph`, or spreading an object where those keys are present but set to undefined.

Common situations: Persisting a minimal/partial workflow record to 'reserve' an ID, migrating older records whose schema predates the required fields, or deserialization dropping optional-looking fields before upsert.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/09ead0b86a27ff1a. Report an issue: GitHub.