Skip to content

Bits of .NET

Daily micro-tips for C#, SQL, performance, and scalable backend engineering.

  • Asp.Net Core
  • C#
  • SQL
  • JavaScript
  • CSS
  • About
  • ErcanOPAK.com
  • No Access
  • Privacy Policy
C#

C#: Fix a Custom Exception That Loses Its Original Stack Trace When Rethrown

- 26.09.26 - ErcanOPAK

🔧 Your Rethrown Exception Lost the Stack Trace That Actually Pointed at the Bug

An exception is caught, logged or wrapped, and rethrown – and the stack trace that shows up afterward points at the RETHROW line, not at where the exception actually originated, because `throw ex;` resets the exception’s stack trace to start fresh from that point, discarding exactly the information you’d need to find the real problem.

🔎 The Problem

try
{
    ParseOrderFile(path);
}
catch (Exception ex)
{
    _logger.LogError(ex, "Failed to parse order file");
    throw ex;   // <- resets the stack trace to THIS line
}

// The stack trace in the rethrown exception now starts at "throw ex;"
// inside this catch block - it no longer shows which line inside
// ParseOrderFile actually threw, which is usually the one piece of
// information you actually need to diagnose the failure.

✅ Fix: Use throw; (No Expression) to Preserve the Original Trace

  • Change `throw ex;` to just `throw;` – the bare `throw` statement rethrows the SAME exception object with its ORIGINAL stack trace fully intact, rather than treating it as a new throw from the current location.
  • If wrapping the exception with additional context is the goal (a common and reasonable pattern), pass the original as the `innerException` parameter: `throw new OrderProcessingException(“Failed to parse order file”, ex);` – this preserves the original exception (and its trace) accessible via `.InnerException`, while still adding your own higher-level context.

⚠️ Why `throw ex;` Ever Seems Reasonable

  • It reads naturally in code review – “catch this, then throw it again” – and it compiles and runs without any warning, which is exactly why this specific mistake shows up in codebases at every experience level; the difference between `throw;` and `throw ex;` is easy to overlook since both look like “just rethrow it”.
  • `Exception.StackTrace` is actually a read-only property populated by the runtime during unwinding – the only way to reset it is by throwing the exception object again as if it were new, which is precisely the behavior `throw ex;` (as opposed to bare `throw;`) triggers.

throw ex isn’t rethrowing the exception – it’s throwing a new one that happens to look the same, and it leaves the trail behind exactly where the mistake was made.

— C# Best Practice

Related posts:

C#: Use Source Generators to Generate Boilerplate Code at Compile Time

C# — async void Event Handlers Swallow Exceptions

C# Required Members: Enforce Mandatory Properties at Compile Time

Post Views: 1

Post navigation

Ajax: Fix a Request That Fires Twice for a Single Button Click on Mobile
Photoshop: Recover Layers Lost After Flattening an Image by Mistake

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

October 2026
M T W T F S S
 1234
567891011
12131415161718
19202122232425
262728293031  
« Sep    

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (951)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (836)
  • How to enable, disable and check if Service Broker is enabled on a database in SQL Server (624)
  • Add Constraint to SQL Table to ensure email contains @ (590)
  • Average of all values in a column that are not zero in SQL (553)
  • How to use Map Mode for Vertical Scroll Mode in Visual Studio (526)
  • Find numbers with more than two decimal places in SQL (468)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps
  • Photoshop: Fix a Color Profile Mismatch That Makes Printed Output Look Nothing Like What You Saw On Screen
  • WordPress: Fix Search Results That Return Pages From a Theme You Deactivated Months Ago
  • Visual Studio: Fix a Test Project That Builds Fine Alone but Fails to Discover Any Tests After a NuGet Restore
  • ASP.NET Core: Fix a File Upload That Times Out on Slow Connections Only Because Kestrel’s Minimum Data Rate Feature Kicked In
  • JavaScript: Fix an Array Destructuring Default Value That Silently Never Applies Because null Was Passed Instead of Undefined

Most Viewed Posts

  • Get the User Name and Domain Name from an Email Address in SQL (973)
  • How to make theater mode the default for Youtube (951)
  • How to add default value for Entity Framework migrations for DateTime and Bool (939)
  • Get the First and Last Word from a String or Sentence in SQL (847)
  • How to select distinct rows in a datatable in C# (836)

Recent Posts

  • CSS: Fix a prefers-color-scheme Media Query That Gets Silently Overridden by a Browser Extension’s Forced Dark Mode
  • Git: Fix a Merge Commit That Silently Drops a File Because Both Branches Deleted It Differently
  • HTML5: Fix a Native Lazy-Loading Image That Never Loads Because It Sits Inside a Hidden Tab Until the User Clicks It
  • The AI Prompt That Traces a Null Reference Exception Back to the Exact Line That First Produced the Null
  • The AI Prompt That Turns a Gym Membership Contract’s Fine Print Into a Plain-English List of Cancellation Steps

Social

  • ErcanOPAK.com
  • GoodReads
  • LetterBoxD
  • Linkedin
  • The Blog
  • Twitter
© 2026 Bits of .NET | Built with Xblog Plus free WordPress theme by wpthemespace.com