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

  1. Move the mapping to the top level of the workflow graph; restructure so composites receive pre-mapped inputs.
  2. Rebuild the workflow with the fluent builder (`.parallel()/.branch()/.foreach()`) so invalid nesting is rejected at build time.
  3. Fix the stored graph JSON by relocating the mapping entry out of the composite.
  4. 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

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


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