Dropped Exception
ID |
csharp.dropped_exception |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
CSharp |
Tags |
CWE:391, exception-handling, reliability |
Description
Reports catch clauses whose body is non-empty yet silently discards the caught exception:
the variable is never referenced, no throw statement re-raises the failure and no logger
call is made.
Rationale
Swallowing an exception turns a recoverable, observable error into a ghost bug. The operator never learns that the operation failed; the tooling never records a stack trace; downstream code keeps running on inconsistent state. The catch block exists for control flow but loses every shred of diagnostic information the runtime tried to hand over.
Empty catch blocks are reported by a sister rule (csharp.empty_catch_block). This rule
covers the more insidious case where the catch body looks busy but never acts on the
exception itself.
A reference to the caught variable inside the when exception filter also counts as
handling, even when the body itself never touches it: catch (Exception ex) when
(ex.Message.Contains("locked")) inspects the exception to decide whether this clause
handles the failure at all, which is exactly the signal this rule looks for — just read
from the filter instead of the body.
public void LoadOk(string path)
{
try { File.ReadAllText(path); }
catch (IOException ex) // FLAW — ex is never used
{
retries++;
attempts.Add(path);
}
}
public void LoadLogged(string path)
{
try { File.ReadAllText(path); }
catch (IOException ex) // OK — logged
{
logger.LogError(ex, "load failed");
}
}
public void LoadRethrow(string path)
{
try { File.ReadAllText(path); }
catch (IOException) // OK — rethrows
{
Cleanup();
throw;
}
}
public void LoadFiltered(string path)
{
try { File.ReadAllText(path); }
catch (IOException ex) when (ex.Message.Contains("locked")) // OK — ex is used in the filter
{
retries++;
}
}