{"record":{"id":"160baf26ef9ae6df","repo":"mastra-ai/mastra","slug":"foreach-step-cannot-iterate-a-mapping-mappings-pr","errorCode":null,"errorMessage":"Foreach step cannot iterate a mapping: mappings project data, they don't execute per item. Use an agent, tool, or plain step as the foreach body.","messagePattern":"Foreach step cannot iterate a mapping: mappings project data, they don't execute per item\\. Use an agent, tool, or plain step as the foreach body\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/workflows/dynamic/rehydrate.ts","lineNumber":130,"sourceCode":"      const date = entry.date instanceof Date ? entry.date : new Date(entry.date);\n      if (Number.isNaN(date.getTime())) {\n        throw new Error(`Stored sleepUntil \"${entry.id}\" has an unparseable date: ${String(entry.date)}`);\n      }\n      const live: StepFlowEntry = { type: 'sleepUntil', id: entry.id, date };\n      wf.__pushStepFlowEntry(live, { type: 'sleepUntil', id: entry.id, date });\n      return;\n    }\n    case 'parallel': {\n      const live: StepFlowEntry = {\n        type: 'parallel',\n        steps: entry.steps.map(s => rehydrateSingleEntry(s, mastra, schemaOpts)),\n      };\n      wf.__pushStepFlowEntry(live, entry);\n      return;\n    }\n    case 'foreach': {\n      if (entry.step.type === 'mapping') {\n        throw new Error(\n          `Foreach step cannot iterate a mapping: mappings project data, they don't execute per item. Use an agent, tool, or plain step as the foreach body.`,\n        );\n      }\n      const live: StepFlowEntry = {\n        type: 'foreach',\n        step: rehydrateSingleEntry(entry.step, mastra, schemaOpts),\n        opts: { concurrency: entry.opts?.concurrency ?? 1 },\n      };\n      wf.__pushStepFlowEntry(live, entry);\n      return;\n    }\n    case 'step': {\n      const live = rehydrateSingleEntry(entry, mastra, schemaOpts);\n      wf.__pushStepFlowEntry(live, entry);\n      return;\n    }\n    case 'workflow': {\n      const nested = assertWorkflowExists(mastra, entry.workflowId);","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/workflows/dynamic/rehydrate.ts#L112-L148","documentation":"In dynamic workflows, `foreach` executes a concrete step (agent, tool, or plain step) once per item, while a `mapping` entry is a pure data projection executed once. Iterating a mapping is semantically meaningless, so rehydrateWorkflow rejects it with this explanatory error instead of silently producing a broken graph.","triggerScenarios":"A stored workflow graph contains a foreach entry whose `step` field is `{ type: 'mapping', ... }` — e.g. built via a UI that allowed nesting foreach around a map() projection, or a hand-edited stored definition.","commonSituations":"Builder UI bugs letting users pick a mapping as the foreach body; users confusing map (projection) with foreach (iteration) and modeling a per-item transformation as a mapping; imported definitions from other formats where map-over-items exists.","solutions":["Replace the foreach body with an agent, tool, or plain step that processes a single item.","If a per-item transformation is needed, move the projection into the foreach step's own map/extract of the item, or use a mapping outside the foreach.","Re-save the corrected graph to storage so the invalid combination is gone."],"exampleFix":"// before\n{ type: 'foreach', id: 'f', step: { type: 'mapping', id: 'm', mapConfig: '...' } }\n// after\n{ type: 'foreach', id: 'f', step: { type: 'tool', id: 't', toolId: 'processItem' } }","handlingStrategy":"validation","validationCode":"function assertForeachBody(entry) {\n  if (entry.type === 'foreach' && entry.step?.type === 'mapping') {\n    throw new TypeError(`Foreach step \"${entry.id}\" cannot iterate a mapping; use an agent, tool, or plain step`);\n  }\n}","typeGuard":"function hasExecutableForeachBody(e: { type: string; step?: { type?: string } }): boolean {\n  return e.type !== 'foreach' || (e.step?.type !== undefined && e.step.type !== 'mapping');\n}","tryCatchPattern":"try {\n  const wf = await rehydrateWorkflow(stored, mastra);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('cannot iterate a mapping')) {\n    // replace the foreach body with an agent/tool/plain step and re-save\n  }\n  throw e;\n}","preventionTips":["Never nest a mapping step as a foreach body when building graphs.","Constrain builder UIs to executable step types (agent/tool/step) for foreach bodies.","Validate graph structure before persisting workflows.","Understand the semantics: mapping projects data once; foreach executes per item."],"tags":["workflow","foreach","validation"],"backgroundTag":"invalid-workflow-graph","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}