mastra-ai/mastra · error · Error
${describeBadPlaceholder(template, idx, rawExpr)} resolved t
Error message
${describeBadPlaceholder(template, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${(err as Error).message}). Drill into a primitive path (e.g. ${${rawExpr}.someField}) or reshape the value in a preceding step. What it means
When a template placeholder resolves to an object (or array), it is serialized with JSON.stringify for interpolation. If the resolved value cannot be stringified (e.g. circular references or BigInt values), stringifyTemplateValue throws advising the user to drill into a primitive field or reshape the value upstream.
Source
Thrown at packages/core/src/workflows/mapping-template.ts:123
}
return ids;
}
/**
* Coerces a resolved placeholder value to a string. Primitives are stringified
* the normal way; objects and arrays are JSON-encoded so downstream agents can
* consume complex step outputs (e.g. `foreach(agent)` returns `{ text }[]`)
* directly in a template. `null`/`undefined` render as empty. If JSON encoding
* fails (circular references, BigInt, etc.), throws with a hint pointing at
* the offending placeholder.
*/
function stringifyTemplateValue(v: unknown, template: string, idx: number, rawExpr: string): string {
if (v === null || v === undefined) return '';
if (typeof v === 'object') {
try {
return JSON.stringify(v);
} catch (err) {
throw new Error(
`${describeBadPlaceholder(template, idx, rawExpr)} resolved to a value that could not be JSON-stringified ` +
`(${(err as Error).message}). Drill into a primitive path (e.g. \${${rawExpr}.someField}) or reshape the value in a preceding step.`,
);
}
}
return String(v);
}
/**
* Resolves `${<scope>.<path>}` placeholders against the implicit namespaces
* available in a step's execute context. See the `.map()` overload signature
* for the full list of accepted scopes (`inputData`, `initData`, `state`,
* `requestContext`, `stepResults.<stepId>`).
*/
export function resolveTemplate(template: string, ctx: any): string {
let idx = 0;
return template.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr: string) => {
idx++;View on GitHub (pinned to 75dd419e61)
Solutions
- Reference a concrete primitive path instead of the whole object: "${stepResults.myStep.id}".
- Convert BigInt/circular fields to strings/numbers in the producing step before mapping.
- If the whole object is needed, JSON-serialize it safely in the prior step (e.g. a JSON.stringify with replacer) and reference that string.
Example fix
// before
prompt.push('${stepResults.dbRow}'); // row contains BigInt
// after
prompt.push('${stepResults.dbRow.id}'); Defensive patterns
Strategy: validation
Validate before calling
function isJsonSerializable(v: unknown): boolean {
try { JSON.stringify(v); return true; } catch { return false; }
}
// before mapping: if (!isJsonSerializable(stepOutput)) normalize it upstream Type guard
function isPlainSerializable(v: unknown): boolean {
if (typeof v === 'bigint') return false;
if (typeof v !== 'object' || v === null) return true;
try { JSON.stringify(v); return true; } catch { return false; }
} Try / catch
try {
run.workflow.mapVariable({ value: '${stepResults.myStep}' });
} catch (err) {
if (err instanceof Error && err.message.includes('could not be JSON-stringified')) {
console.error('Value contains BigInt/circular refs; drill into a primitive path');
} else throw err;
} Prevention
- Interpolate primitive fields, not whole objects, into string templates.
- Convert BigInt values to string/number at step boundaries (e.g. DB/ORM rows).
- Avoid returning class instances with circular references from steps.
When it happens
Trigger: A placeholder like "${stepResults.myStep}" resolves to an object containing a circular reference or BigInt (e.g. a BigInt field, class instances with cyclic refs), and the value is interpolated into a string template.
Common situations: Steps returning database rows/ORM entities with cycles; BigInt IDs from blockchain or DB drivers; returning whole response objects instead of primitive fields into string templates.
Related errors
- DATASET_ITEM_PAYLOAD_NOT_SERIALIZABLE
- Cannot rehydrate conditional step: missing or mismatched pre
- Cannot rehydrate loop step: missing declarative predicate or
- Unknown stored step type: ${JSON.stringify(_exhaustive)}
- Sleep step "${entry.id}" cannot be stored: dynamic duration
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/37781d6d9b5ea3da.
Report an issue: GitHub.