47

I have a class containing something like the following:

public static class Config
{
    private static Lazy<ConfigSource> _cfgSrc = new Lazy<ConfigSource>(
        () => { /* "ValueFactory" here... */ },
        true);

    public static ConfigSource ConfigSource
    {
        get { return _cfgSrc.Value; }
    }
}

In accessing the ConfigSource property, I encountered this InvalidOperationException:

ValueFactory attempted to access the Value property of this instance.

I don't see anything in my "value factory" method that accesses the Value property. Is there anything else that could be triggering this exception? This problem only happens intermittently, but once it does, it takes resetting IIS to clear up the Exception (which appears to be cached once it occurs).

Richard Schneider
  • 34,944
  • 9
  • 57
  • 73
Jacob
  • 77,566
  • 24
  • 149
  • 228
  • 2
    Can you post the code in `/* "ValueFactory" here... */`, or at least some code that makes it crash? The problem might be there. – Alxandr Jun 09 '11 at 23:24
  • Multithreaded execution per chance? – Gleno Jun 09 '11 at 23:25
  • @Gleno, wouldn't the `true` argument ensure that locks will be used to prevent instantiation on multiple threads? – Jacob Jun 09 '11 at 23:27
  • @sixlettervariables, you should post that as an answer. The cached exception that gets thrown doesn't have an inner stacktrace pointing to the problem, but maybe the first time it is thrown it does. – Jacob Jun 09 '11 at 23:28
  • @Alxandr, the factory code is too complex to post; after doing manual static analysis, I don't think the factory references the Lazy object; maybe the stacktrace (if I can get one) will help. – Jacob Jun 09 '11 at 23:29
  • @Gleno, there's an overload that takes a Boolean, which basically translates `true` to `LazyThreadSafetyMode.ExecutionAndPublication` – Jacob Jun 09 '11 at 23:30
  • @Jacob, yes, you are right. I forgot that the constuctor was overloaded, there's another to specify the exact type of locking that takes a LazyThreadSafetyMode object. – Gleno Jun 09 '11 at 23:31
  • This issue was happening to me with almost the exact same code as you have above. After reading this post I realized I had a recursive call to "ConfigSource" inside the section you have labeled /* "ValueFactory" here... */. That may not be your issue but it worth a double check. – Brett Allred Dec 04 '12 at 22:29
  • I had the issue in unit tests with AutoMapper, but latest AutoMapper v8.0 fixed the problem https://github.com/AutoMapper/AutoMapper/issues/1847 – Michael Freidgeim Apr 19 '19 at 08:05

7 Answers7

39

It turned out that this error only occurred when trying to inspect the Value property of the Lazy<> in the Visual Studio debugger. Doing so appeared to create a deadlock because the accessing of Value then seemed to hang the thread for a long time until the InvalidOperationException finally occurred. I could never intercept the original Exception, so I couldn't see the inner stacktrace.

I'm just chalking this up as a bug in Visual Studio or their implementation of Lazy<>.

Jacob
  • 77,566
  • 24
  • 149
  • 228
  • 2
    +1 I agree with your thoughts that there is a bug in the implementation of `Lazy` I encountered this same issue today and there are no exceptions raised in my code. To solve my issues I switched to using a property with a `get { return _val ?? (_val = CreateVal()); }` . – Chris Marisic Mar 26 '12 at 18:59
  • 2
    Visual Studio was consistently hanging (indefinitely?) when I tried to step through code in a web-app. On detaching from the process I got this error thrown back to the browser. Unchecking "Enable property evaluation and other implicit function calls" as per http://stackoverflow.com/questions/3536025/why-would-the-vs2010-debugger-hang seems to have sorted it. – mwardm Mar 31 '15 at 17:45
  • I found in my solutions that the issue was caused by a bug in the DefaultRegistry, and that following the stack trace led me towards the issue. – Kevin May 02 '22 at 16:40
19

This has also happened to me with circular dependencies, so if these steps lead you nowhere, try double checking the stacktrace and verifying that there are no circular dependencies.

hermitt
  • 515
  • 4
  • 8
16

ValueFactory attempted to access the Value property of this instance.

It may help somebody, I was able to fix that error by inspecting my entire ValueFactory procedure. In my example, I was creating a simple model and the linked it with some other data but during the linking process I was accessing the Value property in a singleton and that caused the error.

So accessing the Value of a Lazy object inside the ValueFactory throws such an error. As the error message is already indicating ;-)

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Viktor Hofer
  • 370
  • 2
  • 5
  • 1
    Make sure that watch, locals or autos window is not open. It might try to access Value when breakpoint inside ValueFactory is hit. – Fosna Jul 30 '15 at 08:39
8

The behavior of Lazy<T> is to cache exceptions thrown by the ValueFactory. This can lead to potentially confusing behavior due to the paucity of information given in the InvalidOperationException message. Microsoft was made aware of this issue through Connect, however, it is marked as Wont Fix as they feel there is enough information in the exception itself to diagnose the problem.

If there is an inner exception for the IOE you receive, it should (not saying it will) contain enough information to continue onwards. Another possibility is you have a try...catch blocks which rethrows exceptions (throw ex; instead of throw;), you will lose valuable information.

user7116
  • 63,008
  • 17
  • 141
  • 172
8

To make sure your exception isn't cached, use LazyThreadSafetyMode.PublicationOnly as a second parameter, instead of true.

Using true, you'll end up with a LazyThreadSafetyMode.ExecutionAndPublication. This will ensure only one thread enteres the ValueFactory method, but also ensures exceptions will be cached.

  private static Lazy<ConfigSource> _cfgSrc = new Lazy<ConfigSource>(
        () => { /* "ValueFactory" here... */ },
        LazyThreadSafetyMode.PublicationOnly);

See the link sixlettervariables provided for more information.

nicojs
  • 1,879
  • 2
  • 18
  • 34
  • 1
    I don't like that `PublicationOnly` still allows the initialization code to run in multiple threads (even if those extra results are discarded), but that is nice that exceptions aren't cached. – Jacob Nov 10 '11 at 17:40
  • `PublicationOnly` also allows recursive access to the `Value` property of the `Lazy` instance without throwing an `InvalidOperationException`. – Mike Lowery Mar 08 '17 at 18:33
  • @Jacob:Have you got the solutions regarding "I don't like that PublicationOnly still allows the initialization code to run in multiple threads (even if those extra results are discarded), but that is nice that exceptions aren't cached", I am also looking for the solution. – usFarswan Aug 12 '20 at 10:46
0

When lazy loading a configuration, be sure to not call methods that need said configuration. This will recall the configuration loader which starts over the process, resulting in the described error.

In my case, I was logging the loadstate, while the logger required a configuration

Wouter Vanherck
  • 2,070
  • 3
  • 27
  • 41
0

It is indeed caused by nested Lazy instances when one calls another Value in the factory but more specifically it is caused by different publication modes of these Lazy instances e.g. one is PublicationOnly and other is None. I think it is actually a bug in Lazy implementation.

[Test]
public async Task Test()
{
    var innerLazy = new Lazy<string>(() =>
    {
        Thread.Sleep(10);
        return "lazy";
    }, LazyThreadSafetyMode.None);
    var outerLazy = new Lazy<string>(() => innerLazy.Value, LazyThreadSafetyMode.PublicationOnly);

    var task1 = new Task<string>(() => outerLazy.Value);
    task1.Start();
    var task2 = new Task<string>(() => outerLazy.Value);
    task2.Start();

    await Task.WhenAll(task1, task2);

    Assert.That(outerLazy.Value, Is.EqualTo("lazy"));
}
kemsky
  • 14,727
  • 3
  • 32
  • 51