Skip to content

docs / when it breaks

In the template

Errors ruact raises while it compiles a template — component names, tags that do not pair, attributes, <Suspense>, and component contracts. Each stops the page before any HTML is sent.

template compilemessages from ruact 0.0.22

When you finish

  • what each compile-time message means and the change it asks for
  • why the line number in an attribute message has no file next to it

ruact reads every template before Rails compiles it, turning each capitalized tag into a React element. When a tag is wrong, it stops there: the page is an ActionView::Template::Error whose message is one of the ones below, and nothing has reached the browser.

Every message on this page was produced by running ruact 0.0.22’s preprocessor (Ruact::ErbPreprocessor.transform) on the template above it, with the identifier app/views/posts/index.html.erb.

Component not found in manifest, with a suggestion

Section titled “Component not found in manifest, with a suggestion”
app/views/posts/index.html.erb
<h1>Posts</h1>
<PostCrad post={@post} />

Ruact::UnknownComponentErrortemplate compile

ruact: <PostCrad> at app/views/posts/index.html.erb:3 — Component "PostCrad" not found in manifest.
Did you mean "PostCard"?

Why. A capitalized tag is a React component, and its name must be the export of a "use client" file the Vite build knows. This one is two edits from a name the build has, so ruact names it.

Fix. Use the name it suggests.

<PostCrad post={@post} />
<PostCard post={@post} />

The editor on the home page raises this message for a misspelled <LikeButon>, and the gem pins that text byte for byte in spec/readme_demo_message_spec.rb.

Component not found in manifest, no close name

Section titled “Component not found in manifest, no close name”

Ruact::UnknownComponentErrortemplate compile

ruact: <PostTable> at app/views/posts/index.html.erb:3 — Component "PostTable" not found in manifest.
Did you mean to add app/javascript/components/PostTable.jsx and rebuild Vite?
Did you run the Vite build? Run 'npm run build' or start the Vite dev server.

Why. No component in the build is called that. Either the file does not exist yet, or it exists and the build that ruact is reading predates it.

Fix. Create app/javascript/components/PostTable.jsx with "use client" and a named export PostTable. In development, bin/dev runs Vite, which picks it up; elsewhere, run npm run build.

app/views/posts/index.html.erb
<h1>Posts</h1>
<Dialog open={true}>
<p>Delete?</p>

Ruact::ComponentTagErrortemplate compile

ruact: <Dialog> at app/views/posts/index.html.erb:2 is never closed — write `<Dialog ... />` for a component without children, or close it with `</Dialog>`.

Fix. Close it the way the message says: <Dialog open={true} /> when it has no children, or </Dialog> after them.

Ruact::ComponentTagErrortemplate compile

ruact: </Card> at app/views/posts/index.html.erb:2 closes nothing — there is no open <Card> before it.

Fix. Remove the stray </Card>, or add the <Card> it was meant to close.

app/views/posts/index.html.erb
<Card children={@body}>
<p>Hello</p>
</Card>

Ruact::ComponentTagErrortemplate compile

ruact: <Card> at app/views/posts/index.html.erb:1 has content between its tags and a `children={...}` prop — pass one of them.

Fix. Keep one: the content between the tags, or the children={...} attribute.

A component attribute takes one of three forms: {ruby}, "text", or no value at all. Anything else stops at compile time with one of these messages. They read differently from the rest of this page: they start with the problem rather than ruact:, and give the line but not the file — the file is the one named in the error page’s title.

Message Written as Fix
title= holds ERB, which a component attribute cannot run. Pass the Ruby in braces instead: title={...} at line 1: <PostCard title="<%= @post.title %>" /> title="<%= @post.title %>" title={@post.title}
post={} is empty: put a Ruby expression in the braces at line 1: <PostCard post={} /> post={} post={@post}
unclosed quote in title= (a component tag cannot contain `>`, even inside a quoted value: pass the text from Ruby instead) at line 1: <PostCard title="a > title="a > b" title={"a > b"}
title= needs a value: title={ruby} or title="text" at line 1: <PostCard title= /> title= title={@title} or title="Posts"
unclosed brace in prop expression at line 1: <PostCard post={@post /> post={@post post={@post}
unexpected "2fast={true}" in the component's attributes at line 1: <PostCard 2fast={true} /> 2fast={true} an attribute name starts with a letter or _

All six are Ruact::PreprocessorError.

Ruact::ComponentTagErrortemplate compile

ruact: <Suspense> at app/views/posts/index.html.erb:2 is never closed — close it with `</Suspense>`.
app/views/posts/index.html.erb
<% if @show %>
<Suspense fallback="Loading…">
<% end %>
</Suspense>

Ruact::ComponentTagErrortemplate compile

ruact: <Suspense> at app/views/posts/index.html.erb:2 and its </Suspense> at line 4 are not in the same ERB block — an `if`, a loop or a block opens or closes between them. Put both tags inside that block, or both outside it.

Why. What is between a <Suspense>’s tags becomes a block that runs later. An if or a loop that opens on one side and closes on the other cannot be split that way.

next, break, redo or return inside a <Suspense>

Section titled “next, break, redo or return inside a <Suspense>”
app/views/posts/index.html.erb
<% @posts.each do |post| %>
<Suspense fallback="…">
<% next if post.draft? %>
<PostCard post={post} />
</Suspense>
<% end %>

Ruact::ComponentTagErrortemplate compile

ruact: <Suspense> at app/views/posts/index.html.erb:2 — `next` between its tags would apply to the Suspense's own block, not to the loop or block around it. Move it outside the Suspense.

Fix. Skip the draft before the <Suspense> opens: <% next if post.draft? %> goes on the line after the each.

Ruact::PreprocessorErrortemplate compile

ruact: <Suspense> at app/views/posts/index.html.erb:1 — `fallback` and `delay` take literal text, not ERB.

Fix. Write the fallback as text: fallback="Loading…".

When a component declares the props it takes, ruact checks each tag against that declaration while it compiles the template. The messages show where the tag is and quote it.

Ruact::ComponentContractErrortemplate compile

ruact: <LikeButton> at app/views/posts/show.html.erb:7 is missing required prop "postId" — add the required prop "postId".
in: <LikeButton ... />

The same message names a required slot as required slot.

Ruact::ComponentContractErrortemplate compile

ruact: <LikeButton> at app/views/posts/show.html.erb:7 got unknown prop "postID" — did you mean "postId"?.
in: <LikeButton ... />

With no close name, it ends at the prop: got unknown prop "colour". A component that declares passthrough accepts props it does not list, and this check does not apply to it.