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
- Remove surrounding whitespace inside the braces: "${stepResults.myStep}".
- Replace empty "${}" with a concrete scope.path reference or remove the placeholder.
- 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
- Never type spaces inside ${...}; write ${scope.path} exactly.
- Run validateTemplate() in unit tests for every mapping template constant.
- Watch for editor auto-formatting inserting spaces inside braces.
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
- ${describeBadPlaceholder(template, idx, rawExpr)} must be of
- ${describeBadPlaceholder(template, idx, rawExpr)} requires a
- ${describeBadPlaceholder(template, idx, rawExpr)} references
- mapping entries cannot appear inside .parallel(), .branch(),
- Mapping references unknown workflow init-data "${source.init
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/2cb81b234a545596.
Report an issue: GitHub.