Skip to main content

How to Resolve Error "CS0155: The type caught or thrown must be derived from System.Exception" in C#

The Compiler Error CS0155 is a type-safety restriction related to error handling. The message reads: "The type caught or thrown must be derived from System.Exception".

In some programming languages (like C++), you can throw any type of data (an integer, a string, or an enum) to signal an error. C# is stricter. The .NET error handling mechanism (try-catch-throw) works exclusively with objects that inherit from the System.Exception class. If you try to throw or catch a primitive type (like int or string) or a custom class that isn't part of the exception hierarchy, the compiler raises CS0155.

This guide explains the rules of the exception hierarchy and how to structure your custom errors correctly.

Understanding the Exception Hierarchy

In .NET, the structured exception handling mechanism requires a specific contract. The runtime expects an object that contains a stack trace, a message, and inner exception details. Only classes derived from System.Exception contain this infrastructure.

  • Valid: System.Exception, ArgumentNullException, IOException.
  • Invalid: string, int, enum, object, or any class defined as public class MyError { } (without inheritance).

Scenario 1: Throwing Primitives (Strings or Numbers)

This is the most common mistake for developers coming from C++ or JavaScript contexts. You might try to throw a simple error message string or an error code integer.

Example of error

public void ProcessData(string input)
{
if (input == null)
{
// ⛔️ Error CS0155: The type caught or thrown must be derived from System.Exception
// You cannot throw a string literal.
throw "Input cannot be null";
}

if (input.Length > 100)
{
// ⛔️ Error CS0155: You cannot throw an integer error code.
throw 500;
}
}

Solution: Wrap in an Exception Class

You must instantiate a valid exception class and pass your data into its constructor.

using System;

public void ProcessData(string input)
{
if (input == null)
{
// ✅ Correct: Create a new Exception object containing the message
throw new ArgumentNullException(nameof(input), "Input cannot be null");
}

if (input.Length > 100)
{
// ✅ Correct: Use a generic Exception or a custom one for codes
throw new Exception("Error 500: Input too long");
}
}

Scenario 2: Custom Classes Without Inheritance

You might want to create a rich error object containing custom properties (like ErrorCode or Severity). However, defining a plain class is not enough to make it throwable.

Example of error

// A plain class
public class MyDatabaseError
{
public string Details { get; set; }
}

public class Database
{
public void Connect()
{
// ⛔️ Error CS0155: 'MyDatabaseError' is not an Exception.
throw new MyDatabaseError { Details = "Connection failed" };
}
}

Solution: Inherit from Exception

Modify your custom class to inherit from System.Exception (or a specific subclass like ApplicationException).

using System;

// ✅ Correct: Inherits from Exception
public class MyDatabaseError : Exception
{
public MyDatabaseError(string message) : base(message) { }
}

public class Database
{
public void Connect()
{
// Now this is valid
throw new MyDatabaseError("Connection failed");
}
}

Scenario 3: Attempting to Catch Invalid Types

The same rule applies to the catch block. You cannot try to catch a specific type unless that type is an Exception.

Example of error

try
{
// ... code ...
}
// ⛔️ Error CS0155: You cannot catch a string because a string cannot be thrown.
catch (string errorMessage)
{
Console.WriteLine(errorMessage);
}

Solution

Catch System.Exception (or a specific derived type) and access its properties.

try
{
// ... code ...
}
// ✅ Correct
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
note

Non-CLS Exceptions: In extremely rare cases (interacting with non-C# .NET languages), it is technically possible for a CLR language to throw a non-exception object. However, C# wraps these automatically in RuntimeWrappedException. You still catch them using standard catch (Exception ex) or catch (RuntimeWrappedException ex). You never catch the raw object directly.

Conclusion

CS0155 enforces the .NET standard for error reporting.

  1. Exceptions only: Ensure anything appearing after throw or inside catch (...) inherits from System.Exception.
  2. No Primitives: Do not throw strings ("Error") or numbers (404). Wrap them in new Exception("Error").
  3. Check Custom Classes: If throwing a custom object, verify it has : Exception after the class name.