πŸ©Ίβ€‚Troubleshooting

Something is wrong with my deck. What is it, and how do I fix it?

10 min readView as markdown

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

`default`, `corporate-dark`, `minimalist-light`, `creative-gradient`, `ocean-blue`, `forest-green`, `sunset-warm`, `midnight-purple`, `tech-dark`, `startup-bold`, `academic-classic`.

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:

"disc" | "decimal" | "check" | "arrow" | "none".

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:

"default" | "centered" | "top" | "bottom".

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 β€”

`AnimatePresence`, `Canvas`, `CanvasElement`, `CanvasShape`, `ErrorBoundary`, `ErrorOverlay`, `MarqueeRow`, `MasonryBackground`, `Motion`, `MotionContainer`, `MotionList`, `MotionNumber`, `MotionPresence`, `MotionSpotlight`, `MotionStep`, `MotionSteps`, `MotionText`, `MotionTransform`, `NebulaBackground`, `Notes`, `OverviewGrid`, `Presentation`, `PresenterNotes`, `Slide`, `SlideContent`, `TransformSlide`, `TrustedByMarquee`.

Heading is not among them. The content components β€”

53

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.

IntroductionWhat is Narro, and should I be writing markdown or React?
InstallationWhat do I install, and what does the project look like afterwards?
First DeckWhat does a working React deck look like, end to end?
Markdown ModeHow do I split a slide, style one word, or reveal a line β€” without leaving the markdown file?
Writing AI PromptsWhat do I tell an AI so the deck it writes actually builds?
Rules for AI AgentsWhat do I paste into my repo so an agent stops writing decks that build wrong?
React APIWhich component or hook do I import, and what does it take?
CLIWhich command do I run, and what are its flags?
Markdown APIHow do I read, edit, or validate a deck file from my own code instead of by hand?
Component ReferenceWhat props does this component take, and which package do I import it from?
AnimationHow do I reveal a list one line at a time, or move between slides with something other than a cut?
NavigationHow does the audience move through the deck, and how do I present it?
Canvas & PositioningHow do I put something at an exact position instead of in the flow?
Images & MediaHow do I use an image as a background, tint it, or embed a video?
ArchitectureWhich package owns what, and why is the seam where it is?
Transform ModeHow do I zoom and pan across one big canvas instead of cutting between slides?
Import & ExportHow do I get this deck out as PPTX, PDF, or one file I can email?
AI IntegrationHow do I wire an AI assistant up to Narro so it can write and build decks?
ThemingHow do I change the colours, fonts, and overall look of a deck?
Deck TemplatesHow do I define one house style with named layouts my slides can reference, like a PowerPoint master?
TroubleshootingSomething is wrong with my deck. What is it, and how do I fix it?
LimitationsWhat can't Narro do, and what do I do instead?