Weird error: [ArgumentOutOfRangeException: 'count' must be non-negative

Mattias picture Mattias · Nov 22, 2010 · Viewed 8.2k times · Source

I have a site which runs in ASP.NET 3.5, NHibernate 2.2 and Sprint .NET for Dependency Injection. On our test server a rather strange error occurrs, and also almost everytime there are multiple users online. After the problem has occurred, this error is displayed for every user and every request they make - until you do an IISRESET. Then it is all ok again.

Here's the exception:

'count' must be non-negative.
Parameter name: count 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.ArgumentOutOfRangeException: 'count' must be non-negative.
Parameter name: count

Source Error: 
[No relevant source lines]

Source File: c:\Windows\Microsoft.NET\Framework64\v2.0.50727\Temporary ASP.NET      Files\root\4bf9aa39\6dcf5fc6\App_Web_z9ifuy6t.6.cs    Line: 0 

Stack Trace: 
[ArgumentOutOfRangeException: 'count' must be non-negative.
Parameter name: count]
System.String.CtorCharCount(Char c, Int32 count) +10082288
Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectInternal(String name, Type requiredType, Object[] arguments, Boolean suppressConfigure) +3612
Spring.Objects.Factory.Support.AbstractObjectFactory.GetObject(String name) +75
Spring.Objects.Factory.Support.DefaultListableObjectFactory.GetObjectsOfType(Type type, Boolean includePrototypes, Boolean includeFactoryObjects) +365
Spring.Context.Support.AbstractApplicationContext.GetObjectsOfType(Type type, Boolean includePrototypes, Boolean includeFactoryObjects) +136
Spring.Context.Support.AbstractApplicationContext.GetObjectsOfType(Type type) +66


[ActivationException: Activation error occured while trying to get instance of type InfoTextService, key ""]
   Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) in      c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:57
Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance() in c:\Home\Chris\Projects\CommonServiceLocator\main\Microsoft.Practices.ServiceLocation\ServiceLocatorImplBase.cs:90
OurProjectsNamespace.Infrastructure.ObjectLocator.LocateService() +86

Answer

Steven picture Steven · Nov 22, 2010

This is indeed a very wierd error. When you look at the source of the AbstractObjectFactory.GetObjectInternal you will see the following structure:

[ThreadStatic]
private int nestingCount;

protected object GetObjectInternal(...)
{
    const int INDENT = 3;
    bool hasErrors = false;
    try
    {
        nestingCount++;

        if (log.IsDebugEnabled)
        {
            log.Debug("msg" + 
                new String(' ', nestingCount * INDENT));
        }

        // More code: Calls self recursively.
    }
    catch
    {
        nestingCount--;
        hasErrors = true;

        if (log.IsErrorEnabled)
        {
            log.Error("msg" + 
                new String(' ', nestingCount * INDENT));
        }        
    }
    finally
    {
        if (!hasErrors)
        {
            nestingCount--;
            if (log.IsDebugEnabled)
            {
                log.Debug("msg" + 
                    new String(' ', nestingCount * INDENT));
            }        
        }
    }
}

The exception you are seeing must be thrown by one of the three new String(' ', nestingCount * INDENT) calls. That particular string constructor call throws when the supplied value is negative. Because INDENT is a const, nestingCount must have a negative value in that case. nestingCount is a thread-static variable. Thread-static variables are always initialized with their default value (0 in this case) and can't be influenced by other threads. Further more, nestingCount is never used outside this method.

Because nestingCount is thread-static and only used in that method, it is hard to imagine a scenario were nestingCount can get negative. Perhaps in the case of an asynchronous (ThreadAbort) exception, but even this I find hard to imagine. Other option is that the thread-static variable is changed by someone else using reflection.

But the big question is: how to solve this?

Solution:

There's only one thing I can think of and that is reconfigure log4net in a way that debug information isn't logged. When disallowing debug information, the string(char, int) constructor will probably never get called again, which will hide the problem. Not very pretty, but possibly effective. This might work, because the AbstractObjectFactory logs using the log variable that is initialized as follows:

this.log = LogManager.GetLogger(this.GetType());

You can do this by globally disabling the writing of debug information in log4net, or –when you think this is overkill- by configuring log4net to disable debug info for the type Spring.Objects.Factory.Support.DefaultListableObjectFactory (the instance that is actually causes the exception).

Good luck.