Invalid characters for Reporting Services report names

Summary
A list of characters that cannot be used in Reporting Services report names, plus the method that I used to deduce the list.
Feedback
Spotted a mistake? Please let me know.

Introduction

If you publish reports via the Reporting Services web service then you may have discovered that certain characters are not permitted in the report name.

Unfortunately, Microsoft doesn't seem to have published a list of these characters and it's not as simple as just using the list of forbidden Windows filename characters.

List of characters

"$&*+,/:;<=>?@\|

Additional requirements

  • The maximum allowed length for the name is 260 characters.
  • If the name is only 1 character long then space and full stop (period) are also forbidden.
  • The name cannot start or end with a space.

How I deduced the list

When you attempt to publish a report with an invalid name, Reporting Services throws an InvalidItemNameException exception.

If you're not handling this exception then you may see something like this:

Example InvalidItemNameException error message

When I started getting this exception, and when I realised that there was no published list of forbidden characters, I decided to see exactly how Reporting Services was validating the name.

I could see that the exception was being thrown in a method named ValidateAndTrimItemName(). Using .NET Reflector I loaded the Microsoft.ReportingServices.Diagnostics.dll assembly and found the code for ValidateAndTrimItemName():

public static string ValidateAndTrimItemName(string name, string parameterName)
{
    if (name == null)
    {
        throw new MissingParameterException(parameterName);
    }
    if ((name.Length != 0) && (name.Length <= 260))
    {
        string input = name.Trim(NameTrimCharacters);
        if (m_ValidItemNameRegex.Match(input).Success)
        {
            return input;
        }
    }
    throw new InvalidItemNameException(name);
}

This method checks the length of the name and then validates the name with a regular expression.

(Interestingly, the maximum length of the name allowed by this method is 260 characters, which contradicts the exception message above).

I found the declaration for the regular expression in the constructor of the CatalogItemNameUtility class:

static CatalogItemNameUtility()
{
    PathSeparatorString = '/'.ToString(CultureInfo.InvariantCulture);
    NameTrimCharacters = new char[] { ' ' };
    int num = 260;
    m_ValidItemPathRegex = new Regex("\\A(/(\\.[^/]*)?[^/\\. ]([^/]*[^/ ])?)*\\z(?<=\\A[^;\\?:@&=\\+\\$,\\\\\\*<>\\|\"]{0," 
        + num.ToString(CultureInfo.InvariantCulture) + @"}\z)", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
    int num2 = 260;
    m_ValidItemNameRegex = new Regex("\\A(\\..*)?[^\\. ](.*[^ ])?\\z(?<=\\A[^/;\\?:@&=\\+\\$,\\\\\\*<>\\|\"]{0," 
        + num2.ToString(CultureInfo.InvariantCulture) + @"}\z)", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
}

I decided that it wouldn't be practical to decipher the regular expression; instead, I wrote a simple program that tests ASCII characters 32 to 255.

class Program
{
    static void Main(string[] args)
    {
        Regex re = new Regex("\\A(\\..*)?[^\\. ](.*[^ ])?\\z(?<=\\A[^/;\\?:@&=\\+\\$,\\\\\\*<>\\|\"]{0," + 260 + @"}\z)");

        for (int i = 32; i < 255; i++)
        {
            if (!re.IsMatch("foo" + (char)i + "bar"))
            {
                // This character wasn't allowed. Write it to the console.
                Console.WriteLine((char)i);
            }
        }

        Console.ReadKey();
    }
}

Here's the output (as seen in "List of characters"):

Ouptut from regular expression testing program

NB. If the "foo" and "bar" strings are removed then space and full stop (period) will also fail the validation.