Skip to main content

Command Palette

Search for a command to run...

Next.js 15 Tutorial - 28 - Handling Errors in Layouts

Updated
8 min readView as Markdown
R

I am a MERN stack developer. Here to learn and share my knowledge to help other to grow.

We've learned how error.tsx can gracefully handle runtime errors in pages and nested route segments.

But here's a catch most developers miss:

❗️ Errors thrown from a layout.tsx file in the same segment are not caught by that segment’s error.tsx.

If that sounds confusing, don’t worry — this post walks you through a practical example so you’ll never be surprised again.


📦 Folder Structure

Let’s assume the following structure:

/app
 └── products
      ├── layout.tsx
      ├── error.tsx
      └── [productId]
           ├── layout.tsx
           └── page.tsx

Now let’s simulate an error in the [productId]/layout.tsx file — and see how the error boundary behaves (or doesn’t).


🧪 Simulating an Error in layout.tsx

Inside your [productId]/layout.tsx, paste the following:

// app/products/[productId]/layout.tsx
function getRandomInt(max: number) {
  return Math.floor(Math.random() * max);
}

export default function ProductLayout({ children }: { children: React.ReactNode }) {
  if (getRandomInt(2) === 1) {
    throw new Error('Error loading product');
  }

  return (
    <div>
      <h2>Product Layout</h2>
      {children}
    </div>
  );
}

⛔️ Step 1: Add error.tsx in the Same Segment

// app/products/[productId]/error.tsx
'use client';

export default function Error({ error }: { error: Error }) {
  return <div>Error in Product: {error.message}</div>;
}

❌ Result

When you refresh the page, you might expect this error boundary to kick in. But it doesn't.

Instead, you'll see:

  • A runtime error screen

  • Your custom error message in the console

  • No recovery UI from your error.tsx file


🧠 Why This Happens

This behavior has to do with the component hierarchy in Next.js App Router:

  • layout.tsx components render above error.tsx boundaries.

  • So, errors thrown in layout.tsx cannot be caught by error.tsx in the same segment.


✅ Step 2: Move error.tsx to the Parent Segment

To fix this, move your error boundary to the parent segment — in this case, products.

// app/products/error.tsx
'use client';

export default function Error({ error }: { error: Error }) {
  return <div>Top-level Products Error: {error.message}</div>;
}

Now refresh the page again.

✅ Result

  • The error is now caught.

  • Your custom error UI is displayed.

  • The rest of the app (like global layout.tsx, header, footer) continues to render smoothly.


🔁 Summary Table

SegmentError LocationWhere to Put error.tsxCatches Error?
/products/[productId]page.tsx or [reviewId]/page.tsx/products/[productId]/error.tsx
/products/[productId]layout.tsx/products/error.tsx
/products/[productId]layout.tsx/products/[productId]/error.tsx

✨ Takeaways

  • layout.tsx renders before the segment’s error.tsx, so its errors aren't caught there.

  • To catch layout-level errors, place error.tsx in a parent folder.

  • Always think in terms of the component tree, not just folder structure.


🧠 Bonus Tip

Want to simulate a layout failure in development?

Just use:

if (getRandomInt(2) === 1) {
  throw new Error('Something went wrong in layout');
}

Refresh until it breaks — then verify which error.tsx kicks in.


🚀 Final Thoughts

Error boundaries in Next.js App Router are powerful but nuanced. When layouts are involved, be mindful of their place in the render tree:

✅ Pages & children → error boundaries in the same folder
❌ Layouts → error boundaries must be higher up

Understanding this distinction helps you build more resilient, user-friendly apps.



🧩 Presentation Title

Handling Layout Errors in Next.js – Smart Boundaries with error.tsx
🔧 Powered by Revive Coding


Slide 1: 🧠 From Nested Routes to Layouts

  • We've mastered nested route error handling

  • Now let’s go one level higher ➡️ Layouts!

  • Layouts behave differently in the component tree

  • Let’s break it down 👇


Slide 2: 🔍 Layout & Error Boundary – The Caveat

  • error.tsx handles errors in child segments

  • But there's a catch with layout.tsx

  • If an error is thrown inside a layout in the same segment,
    👉 The local error.tsx won't catch it ❌

🧠 Why? Layouts sit above the boundary in the tree!


Slide 3: 🛠️ Demo Setup in VS Code

What we’ll do:

  • Copy error.tsx to productId/ route

  • In layout.tsx, simulate an error with:

if (getRandomInt(2) === 1) {
  throw new Error("🚫 Error loading product");
}

🧪 Expectation: Local boundary handles it
🧨 Reality: App crashes!


Slide 4: 🔍 Error in Layout? App Breaks!

  • Reload the page a few times

  • 🛑 Boom! Unhandled runtime error

  • We see "Error loading product" in the console

  • But ❌ no boundary UI from error.tsx

This proves: Error boundary was skipped due to layout’s position in the tree


Slide 5: ✅ Solution – Move the Boundary Up

  • Move error.tsx to the parent segment — /products/
app/
  products/
    error.tsx ⬅️ move here
    [productId]/
      layout.tsx

Now when we reload:

  • ✅ Layout error gets caught

  • ✅ Boundary UI replaces product content only

  • ✅ Header, Footer, etc., remain unaffected


Slide 6: 🔁 Component Hierarchy Recap

Layout.tsx (productId) ← error not caught here
└─ error.tsx (productId) ❌ Won't work
   └─ page.tsx ✅ Works for children

✔ Move error.tsx to products/
Layout.tsx (productId)
└─ error.tsx (products) ✅ Will catch it

📌 Always place error boundaries above the layout that might fail


Slide 7: 💡 Key Takeaways

  • ❗ Errors from layout.tsx won’t be caught by same-segment error.tsx

  • ✅ Always place error.tsx in parent folder for layout safety

  • 🔧 This allows recovery without crashing full app

  • 💯 Layout-safe boundaries = Stable UX


Slide 8: 📌 Summary

  • Nested segment errors → handled by local error.tsx

  • Layout errors → need parent level error boundary

  • Knowing the component tree = mastering recovery

🧠 Think hierarchy. Catch early. Recover fast.


Slide 9: 🙌 What’s Next?

  • Next: Advanced fallback UIs & retry patterns in layout recovery

  • More control. Better resilience. Real-world edge cases

  • 🔔 Like & Subscribe to Revive Coding to stay updated

  • It’s free and keeps us building better content ❤️


🔧 Bonus: Suggested File Structure After Fix

app/
  products/
    error.tsx       ✅ handles layout + page errors
    [productId]/
      layout.tsx    ⚠️ throw simulated error
      page.tsx      ✅ standard rendering


🎤 Slide 1: 🧠 From Nested Routes to Layouts

Hindi Script:

"नमस्कार दोस्तों!
अब तक हमने सीखा कि nested routes में errors को कैसे handle करना है।
लेकिन अब बारी है एक और ज़रूरी हिस्से की —
और वो है layouts के अंदर error handling
Layout components थोड़े अलग behave करते हैं,
और इस difference को समझना बहुत ज़रूरी है।
चलिए, शुरू करते हैं!"


🔍 Slide 2: Layout & Error Boundary – The Caveat

Hindi Script:

"आपको याद होगा कि error.tsx सभी nested segments के लिए error को catch करता है।
लेकिन layouts के साथ एक छोटा twist है।
अगर layout में ही error आता है, और error.tsx उसी segment में है —
तो वो boundary काम नहीं करेगी।
क्यों? क्योंकि layout component tree में error boundary से ऊपर बैठा होता है।"


🛠️ Slide 3: Demo Setup in VS Code

Hindi Script:

"अब इसको practical तरीके से देखते हैं।
हम error.tsx को [productId] फोल्डर में कॉपी करते हैं।
फिर [productId]/layout.tsx में वही random error logic डालते हैं
जो हमने पहले [reviewId]/page.tsx में यूज़ किया था।

if (getRandomInt(2) === 1) {
  throw new Error("🚫 Error loading product");
}

और अब देखते हैं क्या होता है।"


🔍 Slide 4: Error in Layout? App Breaks!

Hindi Script:

"Browser में जब हम page reload करते हैं और error trigger होता है —
तो UI टूट जाता है, और हमें console में दिखता है "Error loading product"
लेकिन कोई भी error boundary UI render नहीं होता
इसका मतलब है कि error.tsx को ये error मिला ही नहीं।
और यही है हमारा key learning point।"


Slide 5: Solution – Move the Boundary Up

Hindi Script:

"इस problem को solve करने के लिए हमें करना होगा एक छोटा सा adjustment।
हमें error.tsx को [productId] से उठाकर parent segment, यानी /products/ में रखना होगा।
अब जब हम page reload करते हैं:
✅ Layout का error catch होता है
✅ और सिर्फ product की content replace होती है
✅ बाकी UI — जैसे header, footer — वैसा का वैसा रहता है"


🔁 Slide 6: Component Hierarchy Recap

Hindi Script:

"चलिए hierarchy को एक बार फिर से समझते हैं।

Layout.tsx (productId) ← error not caught here  
└─ error.tsx (productId) ❌ Won’t work  
   └─ page.tsx ✅ Works for children

जब हम error.tsx को /products/ में रखते हैं —
तब ही layout level error सही से catch होता है।"


💡 Slide 7: Key Takeaways

Hindi Script:

"तो दोस्तों, कुछ बातें हमें पक्के तौर पर याद रखनी चाहिए:
❗ Layout.tsx के errors को उसी segment का error.tsx handle नहीं कर सकता
✅ Boundary को parent folder में रखें
🔧 इससे आपका app stable रहता है और टूटता नहीं
💯 Layout-safe boundaries = Better UX"


📌 Slide 8: Summary

Hindi Script:

"तो एक बार फिर से recap करते हैं:
Nested errors को हम local boundaries से संभाल सकते हैं।
लेकिन Layout errors के लिए boundary को ऊपर रखना ज़रूरी है।
इससे हमारा app graceful तरीके से recover कर सकता है।
किसी भी component को stable बनाना है — तो hierarchy को समझना सबसे बड़ा हथियार है।"


🙌 Slide 9: What’s Next?

Hindi Script:

"आगे हम बात करेंगे advanced fallback UIs और retry patterns की —
जिससे हमारी layout recovery और भी स्मार्ट हो जाएगी।
अगर ये वीडियो आपके काम आया हो — तो Like करें, Subscribe करें, और Revive Coding को support करें।
ये हमें motivation देता है और आपके लिए ज़्यादा quality content लाने में मदद करता है।
मिलते हैं अगले वीडियो में — तब तक के लिए, Happy Coding!"


More from this blog

R

Revive Coding

184 posts

Join Revive Coding on Hashnode for JavaScript, React, Node.js tutorials, tips, and articles. Enhance your skills with 800+ monthly visitors! 🚀 #WebDev #CodingTips