{"record":{"id":"e3d649812dc83440","repo":"mastra-ai/mastra","slug":"save-workflow-requires-a-mastra-context","errorCode":null,"errorMessage":"save-workflow requires a Mastra context.","messagePattern":"save-workflow requires a Mastra context\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/tools/workflows/save-workflow.ts","lineNumber":32,"sourceCode":"\nexport { WORKFLOW_BUILDER_MAPPING_CONFIG_DESCRIPTION as MAPPING_CONFIG_DESCRIPTION } from '@mastra/core/workflows/builder';\n\nexport const workflowDefinitionInputSchema = z.preprocess(\n  normalizeWorkflowBuilderDefinition,\n  workflowBuilderDefinitionSchema,\n);\n\nexport const saveWorkflowTool = createTool({\n  id: 'save-workflow',\n  description:\n    'Persist a Dynamic Workflow definition and live-register it on the running Mastra instance. Supports all ten persisted graph families: agent, tool, mapping, nested workflow, parallel, foreach, sleep, sleepUntil, conditional, and loop. Conditional and loop entries require declarative predicates; JS closures cannot round-trip through storage. After this returns, the workflow is immediately runnable. Call it exactly once with the complete definition; there is no incremental save API.',\n  inputSchema: workflowDefinitionInputSchema,\n  outputSchema: z.object({\n    ok: z.literal(true),\n    id: z.string(),\n  }),\n  execute: async (def, { mastra }) => {\n    if (!mastra) throw new Error('save-workflow requires a Mastra context.');\n    const m = mastra as Mastra;\n    const normalizedDefinition = normalizeWorkflowBuilderDefinition(def);\n\n    // `mastra.addDynamicWorkflow` performs registry pre-flight — a mis-classified\n    // agentId/toolId or unregistered id throws before rehydration with an\n    // actionable message listing every offender. It also rejects JSON Schemas\n    // that use keywords the storage-side converter can't rehydrate\n    // (oneOf/anyOf/allOf/not/$ref/patternProperties/discriminator).\n    await m.addDynamicWorkflow(normalizedDefinition as Parameters<Mastra['addDynamicWorkflow']>[0]);\n    return { ok: true as const, id: normalizedDefinition.id };\n  },\n});\n","sourceCodeStart":14,"sourceCodeEnd":45,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/tools/workflows/save-workflow.ts#L14-L45","documentation":"save-workflow is a sub-agent tool whose execute() only works when the tool runtime provides a Mastra instance via the tool execution context. The library throws this error when the context is missing (mastra is undefined) because persisting a Dynamic Workflow via mastra.addDynamicWorkflow() is impossible without a live Mastra instance to register it on. It is a deliberate guard so the tool fails fast with a clear message instead of an opaque TypeError on a missing dependency.","triggerScenarios":"Calling saveWorkflowTool (id 'save-workflow') outside a Mastra-managed tool execution context, e.g. invoking execute() manually with no second argument, registering the tool in an agent/server that does not pass a Mastra instance into tool execution context, or running it in a harness/test that stubs the context without the mastra field.","commonSituations":"Direct unit-test invocation of the tool's execute function without wiring up a Mastra instance; embedding the tool in a custom runner that skips Mastra's tool-context injection; calling the tool from a code path that bypasses the agent/loop plumbing that normally provides { mastra }.","solutions":["Run the tool through a Mastra agent/workflow execution path so the runtime injects the mastra context.","If invoking execute() directly, pass a context object with a mastra instance: execute(def, { mastra: new Mastra() }) or your existing instance.","If using the tool in tests, create a Mastra instance in the test setup and supply it in the execution context instead of omitting the second argument.","Verify the mastracode SDK version wires the tool's ExecutionContext with mastra; upgrade if the runner strips it."],"exampleFix":"// before\nconst result = await saveWorkflowTool.execute(definition, {});\n// after\nimport { Mastra } from '@mastra/core/mastra';\nconst mastra = new Mastra({ /* agents, workflows, storage */ });\nconst result = await saveWorkflowTool.execute(definition, { mastra });","handlingStrategy":"validation","validationCode":"function assertMastraContext(ctx) {\n  if (!ctx || !ctx.mastra) {\n    throw new Error('save-workflow requires a Mastra context: invoke the tool via a Mastra agent/workflow runner.');\n  }\n  return ctx;\n}\nconst result = await saveWorkflowTool.execute(def, assertMastraContext(execCtx));","typeGuard":"function hasMastra(ctx) {\n  return typeof ctx === 'object' && ctx !== null && 'mastra' in ctx && ctx.mastra != null;\n}","tryCatchPattern":"try {\n  await saveWorkflowTool.execute(def, { mastra });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('requires a Mastra context')) {\n    // fix wiring: re-run through a Mastra-managed execution path\n  } else throw err;\n}","preventionTips":["Always run SDK tools through Mastra's agent/workflow execution so the context (including mastra) is injected.","In tests, build a Mastra instance in beforeAll and pass it in the tool execution context.","Never hand-roll tool runners that omit the ExecutionContext's mastra field.","Add an assertion/helper at the call boundary that fails fast with a descriptive message when mastra is missing."],"tags":["mastra","tool-context","workflow","configuration"],"backgroundTag":"missing-execution-context","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}