🔧 The Request Body That Bound to null Because It Was the Wrong Shape
Minimal API model binding reads the request body and tries to deserialize it directly into whatever parameter type the endpoint declared. When a client sends a JSON object and the parameter is a record expecting one, this is seamless. When a client instead sends a bare JSON array to an endpoint whose parameter expects an object, binding doesn’t try to be clever about adapting one shape into the other – it simply fails to produce a value, and the parameter comes through as null, with nothing at the HTTP level making that mismatch obvious until a NullReferenceException further inside the handler explains it indirectly.
🔎 The Problem
app.MapPost("/products/bulk-tag", (ProductTagRequest request) =>
{
// request is null here whenever the client posts a JSON array
// directly, because the parameter type expects a single JSON
// OBJECT and minimal API model binding doesn't attempt to adapt
// an array into one - it just gives up and leaves the parameter
// at its default.
return Results.Ok(request.ProductIds.Count);
});
public record ProductTagRequest(List<int> ProductIds, string Tag);
// Client sends: [1, 2, 3] -> request binds to null, throws
// Client sends: {"productIds":[1,2,3],"tag":"sale"} -> binds fine
✅ Fix: Match the Parameter Type to What’s Actually Being Sent
- Change the client to send the shape the endpoint actually expects (a JSON object wrapping the array), which is usually the right fix when the endpoint is also meant to accept other fields alongside the array.
- When the endpoint is genuinely meant to take a bare JSON array, change the parameter type itself to List<int> (or the appropriate element type) directly, rather than wrapping it in a record – minimal API binds a top-level array parameter correctly when the type matches what’s actually being sent.
- Add explicit null-checking (or a non-nullable parameter combined with a validation filter) immediately inside the handler, so a shape mismatch returns a clear 400 response instead of reaching a NullReferenceException further into the method.
⚠️ Why This Is Easy to Miss
- The request compiles, the endpoint registers without error, and a request sent with the correct shape works perfectly during manual testing – the mismatch only shows up against a specific client or a specific payload shape nobody happened to test with the wrong shape.
- Swagger/OpenAPI tooling generated from the endpoint signature describes the object shape minimal API is expecting, but says nothing about what happens when a caller sends something structurally different, which is exactly the gap that lets this ship unnoticed.
Minimal API binding doesn’t fail loudly when the shapes don’t match – it just leaves you holding null and lets the NullReferenceException further down explain the mistake for it.
