remix: [Bug]: Loader data gets undefined when an error is thrown in a child route

Which Remix packages are impacted?

  • remix (Remix core)

What version of Remix are you using?

1.0.3

Steps to Reproduce

I couldn’t reproduce the bug with the remix template on Codesandbox, but this happens 100% of the time with the Remix Jokes tutorial. You can watch the bug in action at this moment in @kentcdodds’s lifestream yesterday. He asked if someone could open up an issue for it, so here I am.

I have created a public repo on Github with the code you are supposed to have when you have been following along the Jokes tutorial, just before beginning the “SEO with Meta tags” part. Here’s how to see the bug in action:

  1. Clone this repo
  2. Run npm i
  3. Create a .env file and add DATABASE_URL="file:./dev.db" in it, along with SESSION_SECRET="whatever"
  4. Seed the DB: npx prisma db seed
  5. Run the app: npm run dev
  6. Click “Read jokes”, then “Add your own” (or go to http://localhost:3000/jokes/new)
  7. Submit the form
  8. Kaboum!

Expected Behavior

An error thrown in a route action should be caught by the route’s error boundary (or the closest one above). The parent’s loader data shouldn’t become undefined when this happens.

Actual Behavior

The error occurring in the /jokes/new route action function isn’t handled by the route’s error boundary, instead, the /jokes route loader data becomes undefined, triggering an error that is caught by the root error boundary:

TypeError: Cannot read property 'user' of undefined
    at `{data.user ? (` (./app/routes/jokes.tsx:50:16)
    [...]

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 12
  • Comments: 24 (11 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve added empty CatchBoundary to routes/jokes.tsx like this and it fixed it for me.

export function CatchBoundary() {}

Not sure why

Hi, Is there a fix for it (not a temporary fix)? If not, in the meanwhile, can you add the temporary fix to the docs?

Found another way of fixing it without creating empty CatchBoundary in /jokes you can:

  1. Add <Scripts /> to root.tsx
  2. Use Remix <Form> instead of HTML <form> for delete action.

The way it works <Form> will actually do request via fetch and prevent browser reload. I suspect if action throws an error in no-JS environment with full page reload Remix fails to properly load entryContext from which useLoaderData takes its data.

Updated to v1.6.0 in my jokes-tutorial-app now, and it seems to work much better now! 🎉

Thank you so much for the fix, now I can continue with the tutorial 🥰👍

🤖 Hello there,

We just published version v1.6.0 which involves this issue. If you’d like to take it for a test run please try it out and let us know what you think!

Thanks!

Why should empty boundaries be needed? I don’t think the official solution should be to add empty ErrorBoundarys to every component with an <Outlet />. Maybe Remix can add that automatically though?

This is still a bug with 1.5.0 with the no-JS server side render of an action (form submit) that throws in the Jokes app tutorial.

As a temporary fix I suggest to include placeholder ErrorBoundary and CatchBoundary in parent routes if children can throw an error.

Super confusing, and very frustrating.

Got to the “Add a delete capability …” part of the Jokes tutorial, and getting errors of not being able to read “user” from undefined when I try to click the delete button. The error happens in jokes.tsx, which is the parent route of $jokeId.tsx and it makes no sense. What does the loader data of the parent route have to do with the child route? How can a child route cause a parent route loader data to suddenly be undefined? That’s very confusing, and makes no sense at all to me. Frankly, kind of killed my liking of Remix a bit for now, because I no longer feel I can trust/understand what’s going on. 😕

Telling people to throw random catch/error boundaries around is not a solution.

Is this being actually fixed?

🤖 Hello there,

We just published version v1.6.0-pre.0 which involves this issue. If you’d like to take it for a test run please try it out and let us know what you think!

Thanks!

Sorry for the frustration and negativity. Hope you can forgive me.

I was very excited to try out Remix, and got quite bummed out when I ran into this confusing bug while going through the main tutorial (the in-depth one) in the docs. I was prepared for things not being optimal, but was kind of expecting to at least be able to get through the tutorial without hitting a road-block there already. And when I found this bug-report that was reported several months ago, which seemed a bit forgotten(?), I just felt like sharing that frustration because it seems many beginners going through that tutorial run into the very same issue.

Hitting weird bugs like these when going through official beginner-tutorials feels kind of bad, because it’s very easy to enter “obviously, it’s unexperienced me who must have missed something, I must be dumb, because according to the tutorial that I just did, this should be working”-headspace. Could have shared my experience in a less negative and aggressive way though. Sorry again.

Fully aware that this is a very new framework that’s still under construction, and also fully aware that there’s probably a bunch of other things that are even more important for you guys to get fixed.

I’ve read about so many awesome features, and loved the presentations you guys had at the recent Remix and Reactathon-conferences. I just wanted to check it out for myself finally, instead of just reading blog posts and watching talks, and finally got the chance on a “look into whatever you want”-day at work today. 🙃

Excited to see how things develop further. Am subscribed to this bug, and will check out the tutorial and try to continue when this issue gets fixed. 🚀👍

@Svish I get that you’re frustrated but it sounds like software that has been open sourced for only 6 months is out of your risk tolerance. Workarounds are part of the story in the beginning–always has been, always will be, for every project.

We definitely should have fixed this by now, I agree, but we’re not cool with messages like yours. You have some more productive options than what you’ve done:

  • use a different framework
  • write a failing test case
  • fix it yourself with a PR

At this stage of my life and career in open source I have a pretty low tolerance level for comments like yours. Happy to have you here but consider this a warning. Please tone it down and be a productive member of the community.

Created a PR with explanation why it works this way.

The bug does not need database and secret to be reproduced. Here are slightly faster steps:

  1. check out git@github.com:Xiphe/remix-error-action-loader-undefined.git
  2. run npm install && npm run dev
  3. open localhost:3000/nested/new
  4. Click the button
  5. See Cannot read properties of undefined (reading 'demos') which results from this useLoaderData returning undefined

(moved from https://github.com/remix-run/remix/issues/582)