What the description looked like on the watch page
A description that should have been a paragraph, a blank line and a hashtag line rendered as one paragraph with \n\n sitting in the middle of it in plain text. It was cosmetic, but it appeared on every video that had gone through that upload node.
The field that caused it
The upload node's description field was built like this (references simplified):
={{ $json.description }}\n\n{{ $json.tags.split(', ').slice(0, 4).map(t => '#' + t.replace(/\s+/g, '')).join(' ') }}
It reads naturally: description, blank line, hashtags. The \n\n is sitting between two {{ }} blocks, which is the problem.
A two-line experiment
On a scratch workflow I put both forms into a Set node and looked at the output:
={{ 'desc' }}\n\n{{ 'tags' }} -> desc\n\ntags (backslash, n, backslash, n)
={{ 'desc' + '\n\n' + 'tags' }} -> desc, a blank line, tags
In the first form the \n\n is template text. n8n substitutes the braces and leaves everything else exactly as typed. In the second it is a string literal inside JavaScript, where \n means a newline.
The fix, and the backfill
The live node now builds the whole description as a single expression:
={{ $('Limit to 1 Video').item.json.description + '\n\n' + $('Limit to 1 Video').item.json.tags.split(', ').slice(0, 4).map(t => '#' + t.replace(/\s+/g, '')).join(' ') }}
Fixing the node only helps future uploads. The 16 affected videos were rewritten through the YouTube API's videos.update, replacing the literal sequences in the description with real newlines and leaving the other fields as they were. Then all 18 were read back to confirm none still contained a literal backslash-n.
The habit
Anywhere an n8n field mixes expressions with text that contains \n, put the whole value in one expression. And after any change to how text is published, read one published item back from the platform instead of trusting the execution log. The log records that the upload happened, not what the platform stored.
Where else the same mistake hides
The YouTube description was the field where I noticed it, but the rule is about n8n parameter fields in general, so the same pattern breaks anything that sends text to a platform:
- Telegram and Slack messages built as
{{ $json.title }}\n{{ $json.link }}arrive with a visible backslash-n instead of a line break. - Email bodies in a Gmail or SMTP node, where a plain-text body suddenly has
\nin it. - HTTP Request bodies that send JSON to an API. Here the result depends on the receiving API: some store the two characters, some reject the payload.
- Google Sheets cells, where the cell shows the escape sequence and every later workflow that reads the cell inherits it.
The common factor is always the same: text with an escape sequence typed outside the {{ }} braces of a field in expression mode.
Three ways to write a multi-line field correctly
1. One expression with string concatenation. This is what the live workflow uses now:
={{ $json.description + '\n\n' + $json.hashtags }}
2. A template literal inside the braces. Backticks let you write it more readably, and the escape sequence is still inside JavaScript:
={{ `${$json.description}\n\n${$json.hashtags}` }}
3. Real line breaks in the field. Pressing Enter in the expression editor puts an actual newline character into the template text, and n8n copies that through unchanged, which is what you want. This works, but it is easy to lose when someone later edits the field in a single-line input, so I prefer option 1 for anything that gets published.
For longer texts with several optional parts, a Code node that builds the string and returns it as one field is clearer than any of the three, and it is easier to test.
How to find every affected field on an instance
You don't have to open workflows one by one. The n8n public API returns each workflow's JSON, and a search over the node parameters finds the pattern. A rough filter that worked for me: look for parameter values that start with =, contain }}, and have the two characters backslash and n somewhere outside a pair of braces. In practice I searched for the string }}\n in the exported JSON, then checked each hit by hand. Every hit was a real bug.
For content that was already published, the check has to happen on the platform side. For YouTube that meant reading the videos back with the Data API and searching each description for the literal sequence before and after the backfill.
Frequently asked questions
Why does n8n not convert \n into a line break in my field?
In an expression field, only the parts inside {{ }} are evaluated as JavaScript. A \n typed outside the braces is plain template text, so n8n passes the backslash and the letter n through unchanged.
Does this also happen in Code nodes?
No. In a Code node every string is JavaScript, so '\n' inside quotes is a real newline. The problem only exists in parameter fields that mix template text with expressions.
How do I fix videos or posts that were already published?
Fix the node first, then rewrite the stored text through the platform's API (for YouTube, videos.update), and read every item back afterwards to confirm the literal sequence is gone.
Is a template literal with backticks safe in n8n expressions?
Yes. Template literals are normal JavaScript inside the braces, and escape sequences in them behave as in any JavaScript string.
n8n Automation Hub