CA1064: Exceptions should be public

Property Value
Rule ID CA1064
Title Exceptions should be public
Category Design
Fix is breaking or non-breaking Non-breaking
Enabled by default in .NET 8 No

Cause

A non-public exception derives directly from Exception, SystemException, or ApplicationException.

Rule description

An internal exception is only visible inside its own internal scope. After the exception falls outside the internal scope, only the base exception can be used to catch the exception. If the internal exception is inherited from Exception, SystemException, or ApplicationException, the external code will not have sufficient information to know what to do with the exception.

But, if the code has a public exception that later is used as the base for an internal exception, it is reasonable to assume the code further out will be able to do something intelligent with the base exception. The public exception will have more information than what is provided by Exception, SystemException, or ApplicationException.

How to fix violations

Make the exception public, or derive the internal exception from a public exception that is not Exception, SystemException, or ApplicationException.

When to suppress warnings

Suppress a message from this rule if you are sure in all cases that the private exception will be caught within its own internal scope.

Suppress a warning

If you just want to suppress a single violation, add preprocessor directives to your source file to disable and then re-enable the rule.

#pragma warning disable CA1064
// The code that's violating the rule is on this line.
#pragma warning restore CA1064

To disable the rule for a file, folder, or project, set its severity to none in the configuration file.

[*.{cs,vb}]
dotnet_diagnostic.CA1064.severity = none

For more information, see How to suppress code analysis warnings.

Example

This rule fires on the first example method, FirstCustomException because the exception class derives directly from Exception and is internal. The rule does not fire on the SecondCustomException class because although the class also derives directly from Exception, the class is declared public. The third class also does not fire the rule because it does not derive directly from System.Exception, System.SystemException, or System.ApplicationException.

// Violates this rule
[Serializable]
internal class FirstCustomException : Exception
{
    internal FirstCustomException()
    {
    }

    internal FirstCustomException(string message)
        : base(message)
    {
    }

    internal FirstCustomException(string message, Exception innerException)
        : base(message, innerException)
    {
    }

    protected FirstCustomException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

// Does not violate this rule because
// SecondCustomException is public
[Serializable]
public class SecondCustomException : Exception
{
    public SecondCustomException()
    {
    }

    public SecondCustomException(string message)
        : base(message)
    {

    }

    public SecondCustomException(string message, Exception innerException)
        : base(message, innerException)
    {
    }

    protected SecondCustomException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

// Does not violate this rule because
// ThirdCustomException it does not derive directly from
// Exception, SystemException, or ApplicationException
[Serializable]
internal class ThirdCustomException : SecondCustomException
{
    internal ThirdCustomException()
    {
    }

    internal ThirdCustomException(string message)
        : base(message)
    {
    }

    internal ThirdCustomException(string message, Exception innerException)
        : base(message, innerException)
    {
    }


    protected ThirdCustomException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}