mastra-ai/mastra · error · Error
mapping entries cannot appear inside .parallel(), .branch(),
Error message
mapping entries cannot appear inside .parallel(), .branch(), or .foreach(); they must be top-level.
What it means
Mapping entries (variable mappings, e.g. `mapVariable` results used for `.map()` inputs) are only supported at the top level of a stored dynamic workflow graph. When rehydration finds a 'mapping' entry nested inside a `.parallel()`, `.branch()`, or `.foreach()` composite, it throws because those composites cannot contain mapping entries in the stored format.
Source
Thrown at packages/core/src/workflows/dynamic/rehydrate.ts:307
}
const tool = tryGetToolById(mastra, id);
if (tool) {
return { type: 'step', step: createStepFromTool(tool as any) as unknown as Step };
}
throw new Error(
`Dynamic workflow references step "${id}" which is not registered as an agent or tool on this Mastra instance.`,
);
}
case 'workflow': {
const nested = assertWorkflowExists(mastra, entry.workflowId);
// Same call-site identity rule as top-level nested workflows: run the
// clone under the declared id so results are keyed the way the portable
// definition addresses them.
const step = entry.id && entry.id !== nested.id ? cloneWorkflow(nested as any, { id: entry.id }) : nested;
return { type: 'step', step: step as unknown as Step };
}
case 'mapping':
throw new Error(
`mapping entries cannot appear inside .parallel(), .branch(), or .foreach(); they must be top-level.`,
);
}
}
/**
* Rebuild the object shape that `.map()` accepts. Step sources remain workflow-local
* step IDs because mapping execution resolves them from the run's step results.
*/
function rehydrateMapConfig(cfg: Record<string, any>, mastra: Mastra): Record<string, any> {
const out: Record<string, any> = {};
for (const [key, source] of Object.entries(cfg)) {
if (!source || typeof source !== 'object') {
out[key] = source;
continue;
}
if ('template' in source) {
out[key] = { template: source.template };View on GitHub (pinned to 75dd419e61)
Solutions
- Move the mapping to the top level of the workflow graph; restructure so composites receive pre-mapped inputs.
- Rebuild the workflow with the fluent builder (`.parallel()/.branch()/.foreach()`) so invalid nesting is rejected at build time.
- Fix the stored graph JSON by relocating the mapping entry out of the composite.
- Add a pre-rehydration validation pass that rejects mapping entries nested under composite entries.
Example fix
// before: stored graph
{ type: 'parallel', steps: [{ type: 'mapping', ... }, { type: 'step', ... }] }
// after: mapping hoisted
{ type: 'mapping', ... }, { type: 'parallel', steps: [{ type: 'step', ... }] } Defensive patterns
Strategy: validation
Validate before calling
function assertMappingsTopLevel(graph) {
const COMPOSITES = new Set(['parallel', 'branch', 'foreach']);
for (const e of graph.entries) {
if (COMPOSITES.has(e.type) && Array.isArray(e.steps) && e.steps.some(s => s.type === 'mapping')) {
throw new Error('mapping entry found inside composite; hoist to top level');
}
}
} Type guard
function isTopLevelMapping(e: { type: string; steps?: unknown[] }): boolean {
return e.type === 'mapping';
} Try / catch
try {
const wf = rehydrateWorkflow(stored, mastra);
} catch (err) {
if (err instanceof Error && err.message.includes('mapping entries cannot appear inside')) {
// rebuild graph with mapping hoisted to top level
}
throw err;
} Prevention
- Build graphs with the fluent builder so invalid nesting is rejected at construction time.
- Never hand-author composite entries containing mapping children.
- Run a structural validator over stored graphs before rehydration.
When it happens
Trigger: rehydrateWorkflow processes a stored graph where a 'mapping' entry appears as a child of a parallel, branch, or foreach composite entry. This happens if the stored graph was produced incorrectly, hand-edited, or built by code that placed mappings in nested positions the fluent API would reject.
Common situations: Manually constructing/serializing graph JSON without the fluent builder's guards; migrations that reshaped nested entries; custom code pushing entries directly via internals like `__pushStepFlowEntry`.
Related errors
- Mapping references unknown workflow init-data "${source.init
- Cannot rehydrate conditional step: missing or mismatched pre
- Cannot rehydrate loop step: missing declarative predicate or
- Dynamic workflow references agent "${entry.agentId}" which i
- Dynamic workflow references tool "${entry.toolId}" which is
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/19e1b628067e9a73.
Report an issue: GitHub.