Skip to navigation
9-13 minutes read
By Titus Wormer

Note: Had trouble with something that wasn’t explained here but should be? Please let us know. See § Contribute for how to help.

Troubleshooting MDX

This article goes through several common problems and errors that might occur when using MDX. To understand how the MDX format works, we recommend that you start with § What is MDX. How to use our packages is documented in their readmes. To migrate to the latest MDX, see § Migrating from v1 to v2.

Contents

Problems integrating MDX

ESM

If you’re having problems integrating MDX with different tools, that’s likely due to ESM: ECMAScript modules. They’ve been in the works since 2015, we’ve supported them in MDX files from the start, and in MDX version 2 we completely switched to them. Many tools support ESM already. Most other tools are working hard to support them. Some still require extra configuration.

There’s a great Gist by @sindresorhus which explains in detail how to use ESM with many different tools. If you’re having trouble with MDX, some other tool, and ESM, you’ll likely find what you’re looking for there. Please give it a thorough read. If you’re still having problems, the issue tracker of the tools you’re integrating MDX with might provide the answer.

If you’re having trouble with tools that don’t support ESM, such as Electron, one short-term solution is to use a bundler to make a CJS version.

Expand example of making a CJS bundle

With esbuild, this bundles the ESM package @mdx-js/mdx as CJS in vendor/mdx.js:

Shell
npx esbuild @mdx-js/mdx --bundle --platform=node --outfile=vendor/mdx.js

Problems using MDX

Problems that occur when using MDX typically have to do with the APIs of our packages and how to use them. Please see the documentation of the packages, functions, and options you are using for more info and examples.

`options.renderer` is no longer supported

This error is thrown by @mdx-js/loader, our webpack loader. It was introduced in version 2 to help with migration.

The renderer option allowed arbitrary text to be injected before each compiled MDX file. This was typically used to support frameworks other than React such as Preact. We now have options such as jsxImportSource for that and arbitrary JavaScript can be added with recmaPlugins. Because version 2 uses an AST based approach, it is no longer feasible to support a renderer, so it was removed.

Please see ¶ Preact in § Getting started for how to support Preact. See ¶ Creating plugins in § Extending MDX for how to create plugins.

Incorrect `format: 'detect'`

The full error message is as follows:

Incorrect `format: 'detect'`: `createProcessor` can support either `md` or `mdx`; it does not support detecting the format

This error is thrown by @mdx-js/mdx, our core compiler. It was introduced in version 2 when the format option was introduced.

The format option, when configured with 'detect', allows inferring whether a file is MDX or plain markdown. Based on that information, plugins are configured differently, and with different options. This is impossible with unified.

To detect the format of passed files, please either use compile from @mdx-js/mdx or one of the integrations.

Missing `pragma` in classic runtime with `pragmaImportSource`

This error is thrown by @mdx-js/mdx, our core compiler. It was introduced in version 2 when the jsxRuntime, pragma, and pragmaImportSource options were introduced.

This error is thrown when jsxRuntime is configured with 'classic' (the default is 'automatic'), pragmaImportSource is defined (the default is 'react'), but pragma is defined as a falsey value (the default is React.createElement).

If you are using the classic runtime, you have to define a pragma.

Expected `Fragment` given to `evaluate`

Expected `jsx` given to `evaluate`

Expected `jsxs` given to `evaluate`

These errors are thrown by @mdx-js/mdx, our core compiler. They were introduced in version 2 when evaluate (and evaluateSync) were introduced.

evaluate supports React and other frameworks. But these frameworks must support an automatic JSX runtime that exposes these three exports. If you’re getting this error, that means that either a) the framework does not support the automatic JSX runtime, or b) that you’re not passing them correctly to evaluate.

Please see evaluate in @mdx-js/mdx for examples on how to pass these values.

Problems writing MDX

Problems that occur when writing MDX typically have to do with how to combine JS(X) and markdown. It’s an odd mix of two languages: markdown is whitespace sensitive and forgiving (what you type may not exactly work but it won’t crash) whereas JavaScript is whitespace insensitive and unforgiving (it does crash on typos).

Errors typically fall in these three categories:

  • Not escaping < and { — Escape these (\<, \{) if you mean them as plain text instead of JS(X)
  • Incorrect interleaving — See the rules in ¶ Interleaving in § What is MDX?
  • Broken JavaScript — Make sure the JavaScript you write is valid

Could not parse import/exports with acorn: $error

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when the keywords import or export are found at the start of a line but they are not followed by valid JavaScript. An example is:

import 1/1

The reason for this error is that the parser is expecting a JavaScript import or export statement. If you want the word import or export, make sure it’s not at the start of a paragraph. If you do want an import or export statement, please make sure that it’s valid JavaScript.

Unexpected `$type` in code: only import/exports are supported

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when, after an import or export statement, more JavaScript is found. An example is:

export const a = 1
const b = 2

The reason for this error is that we only allow import and export to define data. If you want to define a variable or function, please export it.

Unexpected end of file in expression, expected a corresponding closing brace for `{`

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when there is an opening curly brace not followed by a closing brace. An example is:

a { b

The reason for this error is that the parser is expecting another curly brace. If you just want a brace but not an expression, escape it: \{. If you do want an expression, please make sure to close it with a closing brace }. If there is a closing brace somewhere, make sure that the braces are each on their own lines with no text before the opening brace and no text after the closing brace, or that there are no blank lines between the braces.

Could not parse expression with acorn: $error

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when there are matching curly braces that, when interpreting what’s inside them as JavaScript, results in a syntax error. An example is:

a {const b = 'c'} d

Another example:

a {!} d

The reason for this error is that the parser is expecting a JavaScript expression. If you just want braces instead of an expression, escape the opening: \{. If you do want an expression, make sure that it’s valid JavaScript and that it is an expression. That means statements (such as if and else and for loops) do not work. If you need complex logic, you can wrap statements and whole programs into an IIFE, or move it out to a different file, export it from there, and import it in MDX.

Could not parse expression with acorn: Unexpected content after expression

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when there are matching curly braces that, and valid JavaScript is inside them, but there’s too much JavaScript. An example is:

a {'b' 'c'} d

The reason for this error is that the parser is expecting a single JavaScript expression yielding one value. If you just want braces instead of an expression, escape the opening: \{. If you do want an expression, make sure that it yields a single value.

Unexpected extra content in spread: only a single spread is supported

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when there are multiple values spread into a JSX tag. An example is:

<div {...values, ...other} />

The reason for this error is that JSX only allows spreading a single value at a time:

<div {...values} {...other} />

Unexpected `$type` in code: only spread elements are supported

Unexpected empty expression

These errors are thrown by our MDX parser. They were introduced in version 2. They occur when something other than a spread is used in braces. An example is:

<div {values} {/* comment */} {} />

The reason for this error is that JSX only allows spreading values:

<div {...values} />

Unexpected end of file $at, expected $expect

Unexpected character $at, expected $expect

These errors are thrown by our MDX parser. They were introduced in MDX version 2. They occur when something unexpected was found in a JSX tag. Some examples are:

<
<.>
</
</.>
<a
<a?>
<a:
<a:+>
<a.
<a./>
<a b
<a b!>
<a b:
<a b:1>
<a b=
<a b=>
<a b="
<a b='
<a b={
<a/
<a/->

The reason for these errors is that JSX has a very strict grammar and expects tags to be valid. There are different solutions depending on what was expected. Please read the error message carefully as it indicates where the problem occurred and what was expected instead.

Unexpected closing slash `/` in tag, expected an open tag first

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when a closing tag is found but there are no open tags. An example is:

</div>

The reason for this error is that only open tags can be closed. You probably forgot an opening tag somewhere.

Unexpected attribute in closing tag, expected the end of the tag

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when attributes are placed on closing tags. An example is:

<h1>Text</h1 id="text">

The reason for this error is that only open tags can have attributes. Move these attributes to the corresponding opening tag.

Unexpected self-closing slash `/` in closing tag, expected the end of the tag

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when a closing tag is also marked as self-closing. An example is:

<h1>Text</h1/>

The reason for this error is that only opening tags can be marked as self-closing. Remove the slash after the tag name and before >.

Unexpected closing tag `</$tag>`, expected corresponding closing tag for `<$tag>` ($at)

This error is thrown by our MDX parser. It was introduced in version 2. It occurs when a closing tag is seen that does not match the expected opening tag. An example is:

<a>Text</b>

The reason for this error is that tags must match in JSX. You likely forgot to open or close one of the two correctly.

Cannot close `$type` ($at): a different token (`$type`, $at) is open

Cannot close document, a token (`$type`, $at) is still open

This error is thrown by our MDX parser. It was introduced in version 2. It typically occurs when markdown and JSX are not interleaved correctly. An example is:

> <div>

The reason for this error is that a markdown construct ends while there are still tags open. See the rules on ¶ Interleaving in § What is MDX?