mastra-ai/mastra · error · Error

${describeBadPlaceholder(template, idx, rawExpr)} has empty

Error message

${describeBadPlaceholder(template, idx, rawExpr)} has empty or whitespace-padded contents. Use ${<scope>.<path>} with no surrounding whitespace.

What it means

validateTemplate parses every ${...} placeholder in a mapping template. An empty expression ("${}") or one with surrounding whitespace ("${ foo }") is rejected because placeholder contents must be exactly <scope>.<path> with no padding. describeBadPlaceholder prefixes the message with the template and placeholder position.

Source

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

    rest: dot === -1 ? '' : rawExpr.slice(dot + 1),
  };
}

/**
 * Validates a `{ template }` source's syntax at workflow-definition time.
 * Throws if any placeholder is empty, whitespace-padded, references an unknown
 * namespace, or is a malformed `stepResults.<stepId>` / `stepResults.<stepId>.<path>` shape.
 *
 * Run-time concerns (does the step actually exist, does the path resolve, is
 * the value a primitive) stay in {@link resolveTemplate}.
 */
export function validateTemplate(template: string): void {
  let idx = 0;
  for (const match of template.matchAll(TEMPLATE_PLACEHOLDER)) {
    idx++;
    const rawExpr = match[1] ?? '';
    if (rawExpr.length === 0 || rawExpr !== rawExpr.trim()) {
      throw new Error(
        `${describeBadPlaceholder(template, idx, rawExpr)} has empty or whitespace-padded contents. ` +
          `Use \${<scope>.<path>} with no surrounding whitespace.`,
      );
    }
    const { scope, rest } = parseTemplatePlaceholder(rawExpr);
    if (scope === 'stepResults') {
      const innerDot = rest.indexOf('.');
      const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
      if (!stepId) {
        throw new Error(
          `${describeBadPlaceholder(template, idx, rawExpr)} must be of the form \${stepResults.<stepId>} or \${stepResults.<stepId>.<path>}.`,
        );
      }
      continue;
    }
    if (scope === 'requestContext') {
      if (!rest) {
        throw new Error(

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Remove surrounding whitespace inside the braces: "${stepResults.myStep}".
  2. Replace empty "${}" with a concrete scope.path reference or remove the placeholder.
  3. Validate templates at build time by calling validateTemplate() in a unit test for each mapping.

Example fix

// before
mapVariable({ value: '${ stepResults.fetchUser }' });
// after
mapVariable({ value: '${stepResults.fetchUser}' });
Defensive patterns

Strategy: validation

Validate before calling

import { validateTemplate } from './mapping-template';
['${stepResults.fetchUser.name}'].forEach(t => validateTemplate(t)); // throws on '${ stepResults.x }' or '${}'

Type guard

function isCleanPlaceholder(expr: string): boolean {
  return expr.length > 0 && expr === expr.trim();
}

Try / catch

try {
  validateTemplate(tpl);
} catch (err) {
  if (err instanceof Error && err.message.includes('whitespace-padded')) {
    tpl = tpl.replace(/\$\{\s*([^}]*?)\s*\}/g, '${$1}');
  } else throw err;
}

Prevention

When it happens

Trigger: Writing "${}" or "${ stepResults.myStep }" (spaces inside braces) in a template passed to mapVariable/map/analyzeMapConfig.

Common situations: Copy-pasting templates from docs with formatting; IDEs/formatters inserting spaces; leaving an empty placeholder after deleting a variable name.

Related errors


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