devlooped/moq · error · ArgumentNullException
Value cannot be null. (Parameter 'value')
Error message
Value cannot be null. (Parameter 'value')
What it means
Moq exposes a replaceable ExpressionReconstructor.Instance, mirroring ExpressionCompiler.Instance. The setter enforces that a reconstructor is always available because delegate-based setups depend on it; assigning null throws ArgumentNullException for parameter 'value' to preserve that invariant.
Solutions
- Assign a valid ExpressionReconstructor instance (the built-in default is an ActionObserver-derived instance).
- Null-check the value before assignment; only swap when the new instance is non-null.
- To restore defaults, cache the original value at startup and reassign that, never null.
- Avoid resetting the static in teardowns unless you own a non-null replacement.
Example fix
// before ExpressionReconstructor.Instance = null; // teardown reset // after ExpressionReconstructor.Instance = new ExpressionReconstructor(); // or restore saved default
Defensive patterns
Strategy: validation
Validate before calling
var reconstructor = ResolveReconstructor();
if (reconstructor == null) throw new InvalidOperationException("Resolved ExpressionReconstructor was null");
ExpressionReconstructor.Instance = reconstructor; Type guard
static bool CanInstall(ExpressionReconstructor? r) => r is not null;
Try / catch
try
{
ExpressionReconstructor.Instance = candidate;
}
catch (ArgumentNullException)
{
// retain default instance
} Prevention
- Treat Instance setters as non-nullable contracts everywhere in Moq
- Save and restore the original instance instead of nulling in teardowns
- Null-check container-resolved values before static assignment
- Document static overrides in shared test infrastructure to avoid accidental resets
When it happens
Trigger: Assigning null to `ExpressionReconstructor.Instance`, e.g. during test cleanup `ExpressionReconstructor.Instance = null;` or when a factory/container yields null.
Common situations: Reset code attempting to clear the override; DI resolution failures producing null; copying configuration code from ExpressionCompiler usage where null-reset seemed acceptable.
Related errors
- Value cannot be null. (Parameter 'value')
- Value cannot be null. (Parameter 'newExpression')
- callback (Argument is null)
- value (Argument is null)
- condition (Argument is null)
AI-assisted analysis of devlooped/moq@89a5be629c (2026-09-16).
Data as JSON: /api/errors/b1c5200ab956b7c3.
Report an issue: GitHub.
Appendix: source
Thrown at src/Moq/ExpressionReconstructor.cs:20
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.
using System;
using System.Linq.Expressions;
namespace Moq
{
/// <summary>
/// A <see cref="ExpressionReconstructor"/> reconstructs LINQ expression trees (<see cref="LambdaExpression"/>)
/// from <see cref="Action"/> delegates. It is the counterpart to <see cref="ExpressionCompiler"/>.
/// </summary>
abstract class ExpressionReconstructor
{
static ExpressionReconstructor instance = new ActionObserver();
public static ExpressionReconstructor Instance
{
get => instance;
set => instance = value ?? throw new ArgumentNullException(nameof(value));
}
protected ExpressionReconstructor()
{
}
/// <summary>
/// Reconstructs a <see cref="LambdaExpression"/> from the given <see cref="Action{T}"/> delegate.
/// </summary>
/// <param name="action">The <see cref="Action"/> delegate for which to reconstruct a LINQ expression tree.</param>
/// <param name="ctorArgs">Arguments to pass to a parameterized constructor of <typeparamref name="T"/>. (Optional.)</param>
public abstract Expression<Action<T>> ReconstructExpression<T>(Action<T> action, object?[]? ctorArgs = null);
}
}
View on GitHub (pinned to 89a5be629c)