Suggest an editImprove this articleRefine the answer for “Why does try...catch not catch errors inside JSX?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)`try...catch` does not catch errors inside JSX because **JSX is not executable code at the moment it is written**, it is a **description of the UI** that React **processes asynchronously and outside your call stack**. **Key point:** component rendering runs inside React itself, so such errors need **Error Boundaries** - the "React version of try/catch" at the UI level.Shown above the full answer for quick recall.Answer (EN)Image## Short answer: > `try...catch` does not catch errors inside JSX, > because **JSX is not executable code at the moment it is written**, > it is a **description of the UI**, which React **processes asynchronously and outside your call stack**. --- ## What happens under the hood When you write something like: ```javascript function App() { try { return ( <div> <UserCard user={user} /> </div> ); } catch (e) { console.error('Error:', e); return <ErrorMessage />; } } ``` it seems like `try...catch` should catch any error inside `UserCard`. But React does not work **directly**: JSX turns into an **object describing the element tree**, and **rendering and running the components happens later, inside React itself**, already **on a different call stack**. --- ## Visually 1. You call `App()`. 2. React calls your component → gets a tree object: ```javascript { type: "div", props: { children: <UserCard user={user} /> } } ``` 3. Then React **itself** calls `UserCard()` later (inside its Fiber algorithm). If `UserCard()` throws an error, it is thrown **inside React**, not at the place where your `try...catch` was. So: ```javascript try { <UserCard user={user} /> // <-- this is not a function call, just a description } catch (e) { // this never gets reached } ``` catches nothing, because the error occurs **later**, while React is running, not at the moment JSX is "read". --- ## An analogy Imagine that JSX is not "execution", but a "blueprint of the interface". You described **what** needs to be drawn, but React draws it "in the background". If an error happens during the "drawing" process, your `try...catch` **will not find out about it**, because the code has long since exited your function. --- ## An example of an error ```javascript function UserCard({ user }) { return <div>{user.name}</div>; // user === undefined → an error } function App() { try { return <UserCard />; // try will not catch it } catch (e) { console.error("Render error!", e); return <h1>Error!</h1>; } } ``` React itself will "catch" the error and propagate it upward - if there is an **Error Boundary** nearby, it shows a fallback. If there is not, the app "crashes" (a white screen). --- ## What actually catches such errors ### 1. **Error Boundary** A class component with `componentDidCatch` or `getDerivedStateFromError`: ```javascript class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } componentDidCatch(error, info) { console.error('Error in component:', error); } render() { return this.state.hasError ? <h1>Something went wrong</h1> : this.props.children; } } ``` Usage: ```javascript <ErrorBoundary> <UserCard /> </ErrorBoundary> ``` Now the error inside `UserCard` **is caught**, and the UI does not crash. --- ### 2. `try...catch` **in events or effects** `try...catch` works if the error is thrown **within your synchronous stack**, for example, in `onClick` or `useEffect`. ```javascript <button onClick={() => { try { throw new Error("Error in the handler"); } catch (e) { console.error("Caught:", e); } }} > Click </button> ``` Here the error is caught, because the code runs directly at the moment of the click. --- ### 3. **Asynchronous errors (**`try...catch` **+ async/await)** ```javascript useEffect(() => { async function loadData() { try { const res = await fetch('/api/data'); const json = await res.json(); setData(json); } catch (e) { console.error("Error while loading:", e); } } loadData(); }, []); ``` Everything works as usual here: the error is caught, because it is thrown inside your execution context. --- ## Why you cannot just wrap everything in try...catch Because React **controls the order of component calls** itself, and may render components: - asynchronously (in concurrent mode); - twice (in Strict Mode); - with deferred execution. `try...catch` simply has no access to those execution stacks. --- ## Summary: | Scenario | Caught by `try...catch`? | Why | | --- | --- | --- | | An error in JSX (`<UserCard />`) | No | Rendering is controlled by React | | An error in `useEffect` | Yes | The code runs in your stack | | An error in `onClick` | Yes | The handler is a regular function | | An error in async code (await) | Yes (if wrapped) | `try...catch` works with `await` | | An error in a component with no Error Boundary | No | React unmounts the tree | --- ## Conclusion: > `try...catch` does not catch errors inside JSX, > because component rendering runs **outside your call stack**, > inside React itself. > > Such errors need **Error Boundaries**, > which are the "React version of try/catch" at the UI level.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.