Skip to content

Why Do Triple Backticks End a Markdown Code Block Too Early?

admin12 min read
Illustration of a markdown code block contains triple backticks closing a README fence too early

README files often mix prose with fenced code samples, and it is common for one of those samples to itself contain a shell command wrapped in three backticks. Trouble starts the moment a writer tries to wrap the whole excerpt in another triple-backtick fence for a blog post, a support answer, or a prompt to an AI assistant. The outer fence closes as soon as it reaches the first bare triple-backtick line inside the excerpt, because a markdown code block contains triple backticks it did not expect to meet as a legitimate closing marker. The rest of the excerpt, including a trailing instruction like Then commit your changes., falls outside the code block and renders as ordinary text. This article explains why that happens under the CommonMark and GitHub Flavored Markdown fence rules, shows two reliable fixes, and demonstrates how to confirm the fix by reading raw HTML output from the site’s Markdown to HTML converter instead of trusting a rendered preview.

The Symptom: A README Excerpt That Loses Its Ending

Picture a hypothetical project file, a README.md, documenting a test command. The source text looks like this before anyone touches it:

# README
To run the checks:
```sh
npm test
```
Then commit your changes.

That excerpt renders fine on its own: a heading, a sentence, a shell command inside a fenced block, and a closing sentence. The trouble starts when a technical writer needs to show this whole excerpt as one quoted example. The natural instinct is to wrap the entire thing in one more triple-backtick fence with a markdown info string:

```markdown
# README
To run the checks:
```sh
npm test
```
Then commit your changes.
```

When this text is converted, the last sentence, Then commit your changes., does not stay inside the fenced block. It appears as ordinary text underneath. The final standalone triple-backtick line does not show up as literal characters either. Because the outer block has already closed, that last line is read as the opening of a new fenced block, and nothing ever closes it. CommonMark and GitHub Flavored Markdown both say an unclosed fence runs to the end of the document, and that a fence with no content after it produces an empty code block. So the end of the example becomes an empty, unterminated code block. This is the behavior the specifications describe; a different Markdown renderer could present an unclosed fence differently, so check the output of the tool you actually use. Either way, the excerpt has been cut in the wrong place.

Why the Outer Fence Closes Early When a Markdown Code Block Contains Triple Backticks

The cause is not the ```sh line. A closing fence in CommonMark and GitHub Flavored Markdown must use the same fence character as the opening fence, contain at least as many consecutive characters, and carry no info string of its own. The line ```sh has an info string, sh, so it can only open a block; it cannot close one. The line that actually closes the outer fence is the bare triple backtick that appears right after npm test. It matches the three backticks that opened the outer ```markdown fence, with nothing else on the line, so the parser reads it as a valid closing marker for the outer block, not as part of the nested example.

This is documented fence behavior, not a bug in any particular tool. The CommonMark specification and the GitHub Flavored Markdown specification both describe closing fences the same way: same character, same or greater length, no trailing info string. A fenced block has no concept of a nested fence of the identical kind. Once a markdown code block contains triple backticks that happen to match the opening fence exactly, the parser has no way to tell they were meant as sample text rather than a real closing line.

Fix It With a Longer Fence When Your Markdown Code Block Contains Triple Backticks

The standard fix is to make the outer fence longer than anything it needs to contain literally. Since the inner example only ever uses runs of three backticks, wrapping the whole excerpt in four backticks is enough:

````markdown
# README
To run the checks:
```sh
npm test
```
Then commit your changes.
````

Here, the opening fence is four backticks with the info string markdown. Every bare triple-backtick line inside the excerpt is too short to close a four-backtick fence, because a closing fence needs at least as many characters as the opening one. Only a line of four or more backticks with nothing else on it, appearing where the closing fence belongs, would end this block. The result is that the whole excerpt, heading, shell example, and trailing sentence, stays inside one continuous fenced block.

If a nested example ever needs its own four-backtick fence, count the longest backtick run anywhere in the content first, then pick an enclosing fence one character longer than that. If you maintain README files that later get pasted into prompts for a language model, the AI Prompt Markdown Editor can format a prompt visually and convert it into Markdown. Its description does not promise anything about fence lengths, so after converting, check by hand that every code fence survived and that any outer fence is still longer than the fences nested inside it.

The Tilde Fence Alternative

A second fix swaps the delimiter character instead of lengthening it. Markdown fences can use either backticks or tildes, and the two characters cannot close each other. Wrapping the excerpt in a tilde fence leaves every backtick, however many appear together, as plain content:

~~~markdown
# README
To run the checks:
```sh
npm test
```
Then commit your changes.
~~~

Three tildes open this block, and only a line of three or more tildes can close it. The nested triple-backtick lines have no special meaning to a tilde fence at all, so there is nothing to count or lengthen. This approach is convenient when the nested content might contain a long, unpredictable run of backticks, for example a generated diff or a sample that already mixes several fence lengths. Reach for the tilde fence when counting backticks feels error-prone, and reach for a longer backtick fence when the surrounding document already leans on backtick fences for consistency.

Both fixes rely on the same underlying rule: a fence only closes when the matching character reaches or exceeds the opening length. Adding a backslash before an inner backtick is not part of this rule and does not reliably protect a fence line, so it is not a substitute for choosing a longer or different fence.

Inspecting the HTML Output Instead of Guessing

Rather than guessing whether a fix worked, check the actual markup. The site’s Markdown to HTML converter pastes into an Input Markdown pane and produces an Output HTML pane that shows source markup, not a rendered preview, which makes it easier to see exactly where one element ends and another begins.

Paste the broken version, the one using a single triple-backtick outer fence, into Input Markdown and click Convert. Based on the fence rule explained above, the outer fence closes at the bare triple-backtick line right after npm test. The ```sh line is not a closing fence, so it stays inside the first block as literal text. Expect the Output HTML pane to show a <pre><code> element holding the heading text, the sentence, the ```sh line, and npm test. After it, expect a separate paragraph element for Then commit your changes.. Under CommonMark, the final triple-backtick line then opens a new fence that never closes, so a second, empty <pre><code> element is the predicted result. This is what the specification predicts, not a measured transcript of the converter, and a renderer may treat the unclosed fence differently, so confirm what the pane actually shows.

Now paste either fixed version, the four-backtick wrap or the tilde wrap, and convert again. This time the entire excerpt, heading text, sentence, nested shell example, and trailing sentence, should sit inside a single <pre><code> pair, with no stray paragraph and no empty trailing block, because the parser never found a valid closing line before reaching the real one. Comparing the two Output HTML results side by side is a faster way to confirm the fix than re-reading the raw Markdown for stray backtick counts.

The converter’s output is documented as an HTML fragment, without a surrounding document, head, or stylesheet, generated with the marked library configured for GitHub Flavored Markdown. That matters here because the pane shows exactly the elements the parser produced, nothing more, which is what you want when the question is where one code block ends and the next piece of text begins.

Language Classes Are Not Syntax Highlighting

The info string after an opening fence, the word markdown or sh in these examples, typically becomes a CSS class on the generated <code> element, written as class="language-markdown" or similar. The site’s documentation for its Markdown to HTML tool shows this pattern with a JavaScript sample producing class="language-js", and the tool is explicit that it does not add syntax highlighting itself. A language class is only a hook: a separate highlighter library can read that class name and apply colors to matching tokens, but the class by itself changes no colors and adds no visual difference in a browser with no such library loaded.

This distinction matters when a README excerpt is reused somewhere that does not load a highlighter. The exported markup will still be technically correct, a <pre> element preserving whitespace and line breaks paired with a semantic <code> element, but it will render as plain monospaced text rather than colored code. If a fenced sample contains literal angle brackets or ampersands that need to survive as visible characters rather than being interpreted as markup, run that snippet through the HTML Encoder / Decoder first so the characters are properly entity-encoded before they reach a page that does not already escape them for you.

None of this affects whether the fence itself closes correctly. Fence matching happens during Markdown parsing, before any class names or highlighting decisions come into play, so fixing a premature close with a longer fence or a tilde fence is a separate step from choosing or wiring up a highlighter.

A Quick Checklist for Nested Fences

Before publishing a README excerpt, a support answer, or a prompt that contains a fenced example inside another fenced example, run through a short checklist:

  • Find the longest run of a single fence character, backticks or tildes, that appears anywhere inside the content you need to preserve literally.
  • Open the outer fence with one more of that same character than the longest inner run, or switch to the other character entirely if the inner content never uses it.
  • Confirm the info string, such as markdown, sits only on the opening line; a closing fence never carries one.
  • Convert the result and read the raw HTML output rather than trusting a rendered preview, since a preview can visually smooth over a block that actually closed in the wrong place.
  • Check that the very last line of the intended excerpt is still inside the same <pre><code> pair as the first line, and that no empty trailing code element appears after it.

The same care applies in the other direction. When you turn formatted content back into Markdown with the HTML to Markdown tool, treat fence handling as a generic converter concern: the tool’s description does not say how it picks fence lengths, so read the resulting Markdown and confirm that any code containing backtick runs still sits inside a fence that those runs cannot close.

Frequently asked questions

Why does a plain triple-backtick line close my outer fence even though I meant it as part of the example?

CommonMark and GitHub Flavored Markdown only check that a closing fence uses the same character and reaches the same or greater length as the opening fence. They have no way to know a nested fence was meant as literal content, so the first bare triple-backtick line ends the block.

Can I escape the backticks inside the fenced block instead of lengthening the fence?

Backslash escaping is not part of the fence-matching rule and is not the documented fix. Lengthening the outer fence or switching to a tilde fence is the reliable way to keep nested backticks literal.

Does a line like “`sh count as a closing fence?

No. A closing fence cannot carry an info string. Because that line has the info string sh, it can only be read as an opening fence, never as the line that ends a block.

Why can't tildes close a backtick fence or the other way around?

The specification ties a closing fence to the same character as its opening fence. A backtick fence only closes on a backtick line, and a tilde fence only closes on a tilde line, so the two never interfere with each other.

How many backticks should the outer fence use if the inner content already has four in a row somewhere?

Count the longest single run of backticks anywhere in the content you need to keep literal, then open the outer fence with at least one more character than that run.

Does the language name after the backticks add syntax highlighting automatically?

No. The site’s Markdown to HTML converter turns an info string into a CSS class such as language-js on the generated code element, but it does not apply any highlighting itself; a separate highlighter library would need to read that class.

How can I confirm a fence fix actually worked?

Paste the Markdown into the Markdown to HTML converter and inspect the Output HTML pane rather than a rendered preview. The whole excerpt should sit inside a single pre and code pair, with no plain paragraph breaking it partway through.

Next steps

A markdown code block contains triple backticks most often by accident, when a real fenced example gets pasted into a larger document without checking what fence length the surrounding text already uses. The fix is never about escaping characters inside the block; it is about making the outer fence longer than anything nested inside it, or switching to a tilde fence so backticks have no special meaning at all. Either approach keeps a full README excerpt, heading, shell command, and trailing instruction, inside one continuous block instead of splitting it partway through.

Confirm the result by reading the actual HTML output rather than a rendered preview, since that is the only place a premature closing fence becomes obvious. For more on shaping README-style content for AI tools, see AI Prompt Markdown Editor: How to Write Structured Prompts That Get Better AI Results.

Related tools and resources on HTML Editor Online:

Sources and further reading

Try it in your browser

Free online editors with syntax highlighting. Open one and start coding, no account needed.

All Tools