← Debugging Guides

阅读中文版本

C# ArgumentNullException: value cannot be null

Fix C# ArgumentNullException by tracing the null source, enabling nullable reference types, and guarding public API boundaries.

beginnerdebuggingcsharpnullability

Symptoms

  • System.ArgumentNullException: Value cannot be null. (Parameter x)
  • An injected dependency or config value is unexpectedly null
  • The exception names a parameter at a deep call site

Possible causes

  • A required constructor or method argument was passed null
  • A configuration or environment value was not set
  • A method returns null where callers assume non-null
  • Nullable reference types are disabled, so the compiler cannot warn

Diagnosis steps

Read the parameter name in the message

Interpretation

The parameter name points at the exact argument that arrived null, narrowing the search.

Trace the null to its origin

Interpretation

Follow the argument back to its assignment; often a config read or a helper returns null.

Enable nullable reference types

<Nullable>enable</Nullable>

Interpretation

The compiler then flags possible null assignments at build time instead of runtime.

Root cause

ArgumentNullException is thrown when a method requires a non-null argument but receives null. In a nullable-disabled codebase the compiler cannot warn, so nulls flow until a guard deep in the call graph throws, making the reported parameter a symptom rather than the root.

Fix

Enable nullable reference types so the compiler tracks nullability, add ArgumentNullException.ThrowIfNull at public boundaries, and validate configuration at startup so missing values fail fast near their source. Return non-null or a clearly optional type instead of null from helpers.

Verify the fix

Re-run with the previously null value supplied; the exception is gone, and a test asserts the boundary throws ArgumentNullException with the correct parameter name when null is passed.

Symptoms

A method throws ArgumentNullException naming a parameter that the caller believed was set. The reported parameter may be far from where null actually originated.

Diagnosis

Use the parameter name and trace backwards:

public void Send(IMessenger messenger) {
    ArgumentNullException.ThrowIfNull(messenger); // fails here
}

Enable nullable types to catch this at compile time.

Fix

Guard boundaries and enable nullability:

#nullable enable
public sealed class Client {
    public Client(HttpClient http) {
        ArgumentNullException.ThrowIfNull(http);
        _http = http;
    }
    private readonly HttpClient _http;
}

Validate configuration at startup.

Verification

Re-run with the dependency wired up; no ArgumentNullException. A test passes null and asserts the guard throws with the expected parameter name.

Preventing the Next Null

Guarding the throw site is a start, but the durable fix is to make null impossible where it matters. Records and constructors with required members, non-nullable parameters once nullable reference types are enabled, and dependency injection that fails at startup if a service is unregistered all move the failure to the composition root where it is easy to read. Where null is genuinely meaningful, model it with a distinct type or an Option-like result instead of a nullable reference, so every consumer handles the absent case explicitly rather than discovering it at runtime deep in a call stack.