ArgumentException Throwing Guidelines

Please read this first: About Dave’s ‘unofficial’ Framework Design Guidelines.


þ DO throw ArgumentException or one of its subtypes for preventable errors.

For example, passing a null reference (Nothing in Visual Basic, nullptr in C++/CLI) for an argument when a value is expected, is an error that could have been prevented by a simple check for null by the caller.

The following method correctly throws an ArgumentNullException and ArgumentException for errors that are both preventable by the caller.

public void WriteToStream(Stream stream)
{
    if (stream == null)
        throw new ArgumentNullException("stream"); // Correct

    if (!stream.CanWrite)
        throw new ArgumentException("'stream' must be writable.", "stream"); // Correct

    // Use stream
}

ý DO NOT throw ArgumentException or one of its subtypes from a method for unpreventable errors or where prevention would be as expensive as calling the method itself.

For example, the following method incorrectly throws an ArgumentException for an error that the user is unable to prevent, without replicating the same check that the method is performing internally.

public int GetSettingAsInt32(string name)
{
    string value = GetSetting(name);

    int result;
    if (!int.TryParse(value, out result))
        throw new ArgumentException(name + " cannot be represented as a Int32.", "name"); // Incorrect

    return result;        
}

Instead, a FormatException would be more appropriate.

public int GetSettingAsInt32(string name)
{
    string value = GetSetting(name);

    int result;
    if (!int.TryParse(value, out result))
        throw new FormatException(name + " cannot be represented as a Int32."); // Correct

    return result;
}

ý DO NOT throw ArgumentException or one of its subtypes if you expect users to catch the exception.

ArgumentException is an indication of a broken contract, and when thrown, should indicate a bug in the calling code. Users should not be forced to catch ArgumentException or one of its subtypes.

For example, the following shows a method that incorrectly throws an ArgumentException to indicate that the server specified by the serverName parameter could not be found.

public void ConnectToServer(string serverName)
{
    if (!TryConnect(serverName))
        throw new ArgumentException("Unable to contact " + serverName, "serverName"); // Incorrect
}

Instead, as this is an error that user is likely to want to handle, ConnectToServer should throw an appropriate existing exception or a custom exception to indicate that it could not connect to the server.

public void ConnectToServer(string serverName)
{
    if (!TryConnect(serverName))
        throw new ServerNotFoundException("Unable to contact " + serverName); // Correct
}

The System.IO.Path class violates the last two guidelines. Its members, such as Path.GetFullPath, throw an ArgumentException when they are passed a path that is not well formed. However, as it does not provide a method to determine whether a path is invalid, it forces users to catch ArgumentException. It would have been better to design it to throw a custom exception instead, such as InvalidPathException, to indicate a bad path.


Related
Framework Design Guidelines Section: 7.3.4 ArgumentException, ArgumentNullException and ArgumentOutOfRangeException

Published Tuesday, June 17, 2008 7:00 AM by David Kean

Comments

Wednesday, June 18, 2008 2:45 AM by Steven

# re: ArgumentException Throwing Guidelines

Dave,

I completely agree with you on the guidelines. I hope your guidelines end up in the 2nd edition of the Framework Design Guidelines.

Amen.

Friday, July 18, 2008 6:55 PM by Jeffrey

# re: ArgumentException Throwing Guidelines

thats a very nice article.....clears up a coupla things I was lookin for while googling them up ...

good thing I landed on ur blog.....

Friday, July 18, 2008 8:17 PM by Jeffrey

# re: ArgumentException Throwing Guidelines

thats a very and concise article on usage of ArgumentEception....

that definitely answers a coupla questions...I had

Wednesday, August 06, 2008 9:10 PM by Bernie (the one you know)

# re: ArgumentException Throwing Guidelines

I have two questions:

1. What's your opinion on localizing the ArgumentException message? None of your examples use resourced strings for the exception message.

Yes, you are right - for the purposes of keeping the examples simple, I never localized the resource strings. In 'real' APIs, you should localize the strings.

2. What about private methods. Should they throw ArgumentExceptions too? This could leak private information (eg: parameter names).

Depends. If your private methods are called by public methods that already validate their parameters - then no. You should be asserting instead - it would/should be considered a bug if a bad argument was passed to one of the private methods. However, there's nothing wrong with public overloads calling a single private method which validates the arguments. In the code basd I'm working on, we have two classes; 'Requires' and 'Assumes'. The former is used when validating arguments from consumers of our public API (and throws ArgumentException), whereas, the later is used by internal and private methods when we don't expect an argument to be bad.

Leave a Comment

(required) 
(required) 
(optional)
(required)