n8n-io/n8n · error · NodeOperationError
Could not replace placeholders in ${key}: ${error.message}
Error message
Could not replace placeholders in ${key}: ${error.message} What it means
Thrown by configureToolFunction when parsing a raw request option block (qs, headers, or body entered as a JSON string with placeholders) and jsonParse with repairJSON:true still fails. The placeholder substitution relies on a parseable JSON skeleton, so an unrepairable skeleton aborts.
Source
Thrown at packages/@n8n/nodes-langchain/nodes/tools/ToolHttpRequest/utils.ts:841
`{${parameter.name}}`,
String(argument),
);
}
set(options, [parameter.sendIn, parameter.key], requestOptionsValue);
continue;
}
set(options, [parameter.sendIn, parameter.name], argument);
}
for (const [key, value] of Object.entries(clonedRawRequestOptions)) {
if (value) {
let parsedValue;
try {
parsedValue = jsonParse<IDataObject>(value, { repairJSON: true });
} catch (error) {
throw new NodeOperationError(
ctx.getNode(),
`Could not replace placeholders in ${key}: ${error.message}`,
);
}
options[key as 'qs' | 'headers' | 'body'] = parsedValue;
}
}
}
if (options) {
options.url = encodeURI(options.url);
if (options.headers && !Object.keys(options.headers).length) {
delete options.headers;
}
if (options.qs && !Object.keys(options.qs).length) {
delete options.qs;
}View on GitHub (pinned to 5ac6606e81)
Solutions
- Open the node's raw JSON input for the named key (the message tells you which: qs/headers/body) and paste it into a JSON linter; fix all syntax errors.
- Switch that input from 'JSON' mode to 'Keypair' mode so the UI guarantees valid structure.
- Remove the offending block and re-enter it field by field.
- Validate the JSON in an external tool before pasting back.
Example fix
// before (headers raw, broken):
{ "Authorization": "Bearer {token", "Accept": "application/json" }
// (missing closing brace in placeholder)
// after:
{ "Authorization": "Bearer {token}", "Accept": "application/json" } Defensive patterns
Strategy: validation
Validate before calling
for (const [key, value] of Object.entries(rawRequestOptions)) {
if (value) {
try { JSON.parse(value); }
catch { throw new Error(`Fix the raw JSON for '${key}' before running: ${value}`); }
}
} Type guard
function isValidJsonString(s: string): boolean {
try { JSON.parse(s); return true; } catch { return false; }
} Try / catch
try { parsedValue = jsonParse<IDataObject>(value, { repairJSON: true }); }
catch (e) { /* surface a clear 'fix raw JSON for key X' message */ } Prevention
- Always lint raw JSON blocks in the node UI before saving.
- Prefer 'Keypair' input mode over 'JSON' to guarantee validity.
- Re-validate raw JSON whenever placeholders are added or renamed.
When it happens
Trigger: The user enters a raw JSON block in the node (Query / Headers / Body tab using 'JSON' input mode) with severe syntax errors — mismatched braces, stray characters, or unbalanced brackets that the repair heuristic cannot fix.
Common situations: Hand-editing the raw JSON and introducing a typo; copy-pasting from a source that mangled quotes; partial edits leaving dangling commas or unclosed objects.
Related errors
- The type ${genericType} is not supported
- The response type must be an object or an array of objects
- Input is not a valid JSON: ${error.message}
- Parameter ${parameter.name} is not a valid JSON: ${error.mes
- The provided workflow is not valid JSON: "${(error as Error)
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/5cd258058a8a3cb5.
Report an issue: GitHub.