mastra-ai/mastra · error · Error

Invalid path ${path} in ${errorLabel}

Error message

Invalid path ${path} in ${errorLabel}

What it means

traverseMappingPath walks a dot-separated path (e.g. "user.address.city") through an object. If any intermediate value along the path is not a non-null object (undefined, null, or a primitive), the path cannot be traversed and it throws identifying the path and the mapping/template label it occurred in.

Source

Thrown at packages/core/src/workflows/mapping-template.ts:19

/**
 * The `${scope.path}` mapping-template DSL used by `.map()` template sources.
 *
 * Definition-time syntax checks live in {@link validateTemplate}; run-time
 * resolution (path lookup + value coercion) lives in {@link resolveTemplate}.
 * This module has no knowledge of the step-entry union — it is a pure
 * string-DSL interpreter over a step's execute context.
 */

/** Walks a dotted path on an object. `''` or `'.'` returns the root unchanged. */
export function traverseMappingPath(root: unknown, path: string, errorLabel: string): unknown {
  if (path === '' || path === '.') return root;
  const parts = path.split('.');
  let value: any = root;
  for (const part of parts) {
    if (typeof value === 'object' && value !== null) {
      value = value[part];
    } else {
      throw new Error(`Invalid path ${path} in ${errorLabel}`);
    }
  }
  return value;
}

const TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;

const TEMPLATE_NAMESPACES = ['inputData', 'initData', 'state', 'requestContext', 'stepResults'] as const;
type TemplateScope = (typeof TEMPLATE_NAMESPACES)[number];

/** Common error-message prefix so every template diagnostic points at the exact placeholder. */
function describeBadPlaceholder(template: string, idx: number, rawExpr: string): string {
  return `Template placeholder #${idx} (\${${rawExpr}}) in '${template}'`;
}

/** Split a placeholder body `scope.path.with.dots` into its leading scope and the dotted remainder. */
function parseTemplatePlaceholder(rawExpr: string): { scope: string; rest: string } {
  const dot = rawExpr.indexOf('.');

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Align the path with the actual step output shape (log the step result to inspect it).
  2. Shorten the path to the last existing object level, or restructure the producing step to emit the nested object.
  3. Use optional/default handling upstream (e.g. normalize the output in the producing step) before mapping.

Example fix

// before
mapVariable({ value: '${stepResults.fetchUser.data.profile.email}' }) // data is a string
// after
mapVariable({ value: '${stepResults.fetchUser.email}' })
Defensive patterns

Strategy: validation

Validate before calling

function assertPath(obj: unknown, path: string): void {
  let cur: any = obj;
  for (const part of path.split('.')) {
    if (typeof cur !== 'object' || cur === null) throw new Error(`Path '${path}' invalid at '${part}'`);
    cur = cur[part];
  }
}

Type guard

function isNonPlainValue(v: unknown): v is Record<string, unknown> {
  return typeof v === 'object' && v !== null;
}

Try / catch

try {
  run.workflow.mapVariable({ value: '${stepResults.myStep.detail.x}' });
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Invalid path')) {
    console.error('Mapping path mismatch with step output shape:', err.message);
  } else throw err;
}

Prevention

When it happens

Trigger: A mapping entry or ${...} template placeholder references e.g. stepResults.myStep.result.detail while stepResults.myStep.result is undefined or a scalar (step output shaped differently than expected).

Common situations: Renaming fields in a step's output without updating downstream mapVariable/toRoute mappings; a step returning a string/number where an object was assumed; optional output fields absent at runtime.

Related errors


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