π©ΊβTroubleshooting
Something is wrong with my deck. What is it, and how do I fix it?
Entries are grouped by what you observe, not by what is wrong, because you arrive here with a symptom rather than a diagnosis. The headings are the literal strings you would search for.
Before reading further: npx @getnarro/cli check deck.md diagnoses most of this
in about a second and names the value that would have worked. Roughly half the
entries below exist because the failure happens without an error, which is
exactly when a checker is worth more than a message.
Failures that produce no error at all
These are the expensive ones. Nothing throws, the build succeeds, and the deck is wrong on screen.
A directive shows up as literal text on the slide
Symptom: the audience sees <!-- .element: class="fragment" --> or
::: note rendered as body copy, instead of the effect it was supposed to have.
Cause: that is Marp, reveal.js, or Slidev syntax. Narroβs dialect is different, and markdown it does not recognise is just text β there is nothing for it to reject. This is overwhelmingly the most common broken deck when the markdown was written by an AI, because those three tools dominate its training data.
Fix: the Narro equivalents are {.class} after an element, <!-- notes: β¦ -->
for speaker notes, and {.step} on a list item for a fragment. Full dialect:
Markdown mode. If a model wrote the deck, paste the
dialect contract from Rules for AI agents into your
projectβs AGENTS.md β otherwise it will regenerate the same syntax next time.
narro check catches this, including when the syntax is Narroβs own and the
element simply did not form. To print the markers on purpose, put them in a code
fence or `inline code`, or escape them β \*\*not bold\*\*.
Everything after ::something:: vanishes
Symptom: half a slide is missing. No error, no warning, no blank space where it should have been.
Cause: the slot name does not exist on that layout, so nothing renders it.
two-column has one named slot and it is called right; ::sidebar:: and
::second:: are inventions.
Fix: run check, which reports this one precisely:
error deck.md:10 (slide 2)
Layout "two-column" has no slot "sidebar", so everything after `::sidebar::`
would not render. Slots for this layout: right.
Slot names describe the position, not the content. See the layout table in Markdown mode.
The deck renders with default styling and ignores the theme
Symptom: a theme: is set in the deck frontmatter, and the deck looks like
it has no theme.
Cause: the theme name does not resolve. Theme ids are kebab-case and
qualified β corporate-dark, not corporate; tech-dark, not tech.
Fix: check catches this as an error and lists every installed theme.
Valid ids are
A frontmatter key does nothing
Symptom: you set aspect-ratio: "16:9" (or color-scheme, or
font-preset) and the deck ignores it.
Cause: frontmatter keys are camelCase. An unrecognised key is not an error β a theme or a custom layout is allowed to read its own keys β so it is kept and ignored.
Fix: check reports it as a warning with the correction:
warning deck.md
Deck frontmatter key "aspect-ratio" is not one the dialect defines, so nothing
reads it unless your theme or layouts do. Did you mean "aspectRatio"?
Deck keys are
`title`, `author`, `date`, `theme`, `template`, `aspectRatio`, `transition`, `class`, `keyboard`, `mouse`, `touch`, `routing`, `favicon`, `maxDuration`;slide keys are
`layout`, `class`, `id`, `transition`, `background`, `notes`.A list renders with plain bullets when you asked for checkmarks
Symptom: <List variant="bullet"> or variant="number" produces the
default marker.
Cause: neither value exists. Listβs variant names the CSS marker, not
the semantic role:
Fix: variant="disc" for bullets, variant="decimal" for numbers,
variant="check" for checkmarks. The component
reference is generated from the types, so it is the
authority on every prop.
You wanted a horizontal rule and got a new slide
Symptom: a --- written as a divider inside a slideβs body starts a new
slide instead of drawing a line.
Cause: --- on its own line is the slide separator. There is no way for
the splitter to tell a thematic break from a slide break, so the slide break
wins.
Fix: use *** or ___, which markdown renders as the same horizontal rule
and the splitter ignores. A --- inside a fenced code block β backticks or
tildes β is safe and does not split.
Errors, with their fixes
Could not parse expression with acorn
Symptom: a deck fails on a line containing {.
Cause: a slide is MDX, so { opens a JavaScript expression unless the block
is Narroβs attribute syntax β {.class}, {#id}, {key=value}. A brace around
anything else, {like this}, is read as code.
The message names the offending character when it can:
βNarroβs attribute syntax does not accept X.β Today the only character that
cannot appear in a class is a literal { or }; arbitrary values
(text-[10px]), opacity modifiers (bg-white/5), fractions, variants
(hover:, md:), half-steps (p-1.5) and ! overrides are all accepted. If
you are on an older version, those all failed here β upgrade rather than
rewriting the deck.
Fix: write \{ for a literal brace, or put the text in `inline code`.
If the block really is a class list containing a brace, move that one class into
deck.css.
β¦ is not attribute syntax, so this container has no classes at all
Symptom: check or build fails on a ::: line, or on a fenced code
blockβs info string.
Cause: a { β¦ } in either position has no second reading β unlike a brace in
prose, which MDX can compile as an expression β so a block that is not attribute
syntax there means the whole class list would be discarded. It used to be
discarded silently: the deck built, check --strict said β looks good, and the
box reached the projector unstyled.
Fix: make it attribute syntax (.class, #id, key=value), or remove it. A
fenceβs info string is ```bash {.rounded-xl} β language first, block last.
β¦ written here but on no element in the compiled slide
Symptom: check names a class you wrote and says nothing renders it.
Cause: the block parsed, the class is legal, and the element it attached to does not exist in the output β most often because the block sits after something that is not an element (an MDX comment, a slot marker) and had nothing to attach to.
Fix: run narro check deck.md --render and look at the element you meant. An
attribute block styles the element it sits against: a list item styles the
<li>, a fence styles the <pre>, a block on its own line styles the block
above it, and one written tight against a word styles the word. Move the block
next to the element you meant.
N slides do not fit the canvas
Symptom: check --fit reports overflow and names an element.
Cause: the slideβs content is taller or wider than the canvas (1920Γ1080 by default), so the audience sees it clipped. Nothing else in the toolchain can see this β a build is silent about layout.
Fix: reduce a font size, a padding, or the amount on the slide; or split the slide. The named element is the last one sticking out, which is usually the one to shrink.
--fit needs a browser and none is installed
Symptom: check --fit measures nothing.
Cause: --fit renders the deck for real, so it needs Chromium. It reports
this rather than passing quietly, and under --strict it fails.
Fix: npx playwright install chromium, or set
NARRO_CHROMIUM=/path/to/chromium if your image already has one.
Expected a closing tag for <br>
Symptom: a deck that used to build now fails on a line of raw HTML.
Cause: raw HTML in a slide is JSX. Earlier versions compiled .md decks as
plain CommonMark, which silently deleted the tag rather than complaining β so
a deck could carry HTML that never rendered and never said so.
Fix: close every tag (<br />, <img β¦ />) and camelCase every attribute
(className, not class). If the HTML was never rendering anyway, deleting it
changes nothing on screen.
Unknown layout "x". Available: β¦
Symptom: check or build exits non-zero with this message.
Cause: the layout: value is not a built-in and there is no matching file
in a layouts/ directory beside the deck.
Fix: use one of
`default`, `cover`, `section`, `quote`, `end`, `two-column`, `three-column`, `image-right`, `image-full`,or create layouts/<name>.tsx next to the deck β the error names that path for
you. check also suggests the closest existing name, so a typo is a one-line
fix.
Note that layout means two different things and they are separate closed
sets. In slide frontmatter it is the layout name above. On the React
SlideContent component it is content alignment:
has no exported member 'Heading' / does not provide an export named 'Heading'
Symptom: TypeScript reports Module '"@getnarro/core"' has no exported member 'Heading' (TS2305), or the browser reports The requested module '@getnarro/core' does not provide an export named 'Heading'. The package
itself resolves fine; only the named import fails.
Cause: @getnarro/core is the presentation runtime plus the motion and
canvas primitives β
Heading is not among them. The content components β
of them, including Heading, Text, List, Code, and Image β are in
@getnarro/shared-ui.
Fix: import content components from @getnarro/shared-ui. The split is
deliberate: shared-ui has no runtime dependency on core, so a deck can use
the components without the presentation runtime. Which package exports what:
https://getnarro.com/components.json, or one component at a time at
https://getnarro.com/llms/Heading.md.
npx narro β¦ installs something that is not Narro
Symptom: npx narro build deck.md downloads a package and then fails in a
way that mentions no Narro command you recognise.
Cause: the npm package named narro is unrelated to this project.
Narroβs packages are all published under the @getnarro/ scope, and the
narro binary comes from @getnarro/cli.
Fix: npx @getnarro/cli <command>. Inside a scaffolded project the local
binary is already on the path, so plain narro build deck.md works there;
outside one, always name the scoped package.
Anti-fix: installing narro globally so the bare command resolves. It is
someone elseβs package, and it will not become Narro.
The deck builds locally and fails in CI or on a fresh clone
Symptom: works on your machine, fails after npm install somewhere else.
Cause: almost always a dependency that resolves through your lockfile but
is not declared, or a file that is not in the packageβs files list.
Fix: reproduce it the way a user hits it β install into a directory outside
your project and build there. Narroβs own repository runs exactly this as a
separate CI job (pnpm test:templates) because the workspace build stayed
green while every published template failed to build, for months.
Still stuck
check reports every problem it finds in one run, so fix them all before
re-running rather than one at a time. If the deck passes check and is still
wrong, the problem is in a place check cannot see β a custom layout
component, a themeβs own CSS, or an MDX component β and build with the
browser console open is the next step.
Something that should have been caught and was not is worth reporting: a recurring troubleshooting entry is a checker feature that has not been written yet.