n8n-io/n8n · warning
CODE_NESTED_TEMPLATE_LITERAL
CODE_NESTED_TEMPLATE_LITERAL
Error message
${namePrefix}Code node uses nested template literals, which often break after save. Build multi-line strings with arrays joined by a runtime separator, e.g. `const LF = String.fromCharCode(10); return lines.join(LF);`. What it means
CODE_NESTED_TEMPLATE_LITERAL is a lint issue. hasNestedTemplateLiteral() walks the AST and reports any TemplateLiteral that contains another TemplateLiteral inside its expression slots. These nested backtick interpolations are known to break after n8n serializes/deserializes the workflow.
Source
Thrown at packages/@n8n/workflow-sdk/src/lint/code-node/js.ts:209
if (options.mode === 'runOnceForEachItem' && disallowedInputMethod !== undefined) {
issues.push(
lintIssue({
code: 'CODE_MODE_API_MISUSE',
message:
`${namePrefix}uses mode: 'runOnceForEachItem' but calls $input.${disallowedInputMethod}(). ` +
`$input.${disallowedInputMethod}() is only available in runOnceForAllItems (the default). ` +
'Switch mode to runOnceForAllItems, or use $input.item / $json for per-item work.',
lintTarget: 'jsCode',
nodeName: options.nodeName,
parameterPath: 'jsCode',
}),
);
}
if (hasNestedTemplateLiteral(ast)) {
issues.push(
lintIssue({
code: 'CODE_NESTED_TEMPLATE_LITERAL',
message:
`${namePrefix}Code node uses nested template literals, which often break after save. ` +
'Build multi-line strings with arrays joined by a runtime separator, e.g. ' +
'`const LF = String.fromCharCode(10); return lines.join(LF);`.',
lintTarget: 'jsCode',
nodeName: options.nodeName,
parameterPath: 'jsCode',
}),
);
}
return issues;
}
/** @deprecated Use lintJsCode — nested templates are detected via AST there. */
export function hasNestedTemplateLiterals(jsCode: string): boolean {
const ast = parseJs(jsCode);
return ast ? hasNestedTemplateLiteral(ast) : false;View on GitHub (pinned to 5ac6606e81)
Solutions
- Build the multi-line string from an array joined by a runtime separator, e.g. const LF = String.fromCharCode(10); return lines.join(LF);
- Flatten the nested template into a single-level template using intermediate variables.
- Move complex string building into a Code node and pass the result forward.
Example fix
// before (Code node jsCode)
return `header
${rows.map((r) => `${r.id},${r.name}`).join('\n')}`;
// after
const LF = String.fromCharCode(10);
const body = rows.map((r) => r.id + ',' + r.name).join(LF);
return ['header', body].join(LF); Defensive patterns
Strategy: validation
Validate before calling
import { lintJsCode } from '@n8n/workflow-sdk/lint/code-node/js';
const issues = lintJsCode(jsCode, { mode });
if (issues.some((i) => i.code === 'CODE_NESTED_TEMPLATE_LITERAL')) {
throw new Error('jsCode has nested template literals; rebuild the string via array join.');
} Prevention
- Avoid backtick templates inside ${ } of another backtick template.
- Build multi-line strings with arrays joined by String.fromCharCode separators.
- Run lintJsCode on generated Code node bodies before saving.
When it happens
Trigger: Code like `${`inner ${value}`}` or `a ${`b ${c}`}` inside jsCode — a backtick template nested inside another backtick template's ${ }.
Common situations: LLM builds a multi-line string with nested template interpolation; developer composes a prompt string by nesting templates; concatenating dynamic fragments inside one outer template.
Related errors
- CODE_NODE_NETWORK_CALL
- CODE_NODE_FORBIDDEN_IMPORT
- CODE_MODE_API_MISUSE
- CODE_NODE_NETWORK_CALL
- SDK_AS_CONST
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/812160fb6ba842a8.
Report an issue: GitHub.