Skip to content

[AsParameters]: unparseable value in a collection query parameter silently binds null instead of returning 400 (scalar case fixed by #3372) #3398

Description

@outofrange-consulting

Summary

#3372 (fixed in 6.17.1 / 6.17.2) made an unparseable scalar query string value return 400 Bad Request instead of silently binding the property's default. The same failure mode is still present for collection / array query string parameters bound through [AsParameters].

When one member of a multi-value query parameter cannot be parsed, the whole collection binds to null and the request succeeds with 200 OK. The endpoint cannot distinguish that from "the caller did not send the parameter at all".

Version

WolverineFx / WolverineFx.Http 6.17.2, .NET 10.

Repro

public enum Colour { Red, Green, Blue }

public record SearchRequest
{
    public Colour[]? Colours { get; set; }
    public Colour? Colour { get; set; }
}

public static class SearchEndpoint
{
    [WolverineGet("/widgets")]
    public static IResult Get([AsParameters] SearchRequest request)
        => Results.Ok(new { colours = request.Colours, colour = request.Colour });
}
Request Actual (6.17.2) Expected
GET /widgets?colour=Purple 400 Bad Request ✅ (fixed by #3372) 400
GET /widgets?colours=Purple 200 OK, Colours == null ❌ 400
GET /widgets?colours=Red&colours=Purple 200 OK, Colours == null ❌ 400

The same holds for int[] / Guid[] / long[] collections, not just enums — any element whose TryParse fails takes the entire collection to null.

Why this is worse than a plain 400

On a filtering/search endpoint, the bound collection is typically used as an optional predicate:

if (request.Colours is { Length: > 0 })
{
    query = query.Where(x => request.Colours.Contains(x.Colour));
}

A typo in one value therefore does not fail the request — it silently removes the filter and returns an unfiltered result set with a 200, while the caller believes the results are filtered. That is a silent-wrong-answer failure mode rather than a loud one.

Validation cannot compensate

FluentValidation (via WolverineFx.Http.FluentValidation) sees null, not an out-of-range value, so neither of these fires:

RuleForEach(x => x.Colours).IsInEnum();          // no elements to iterate
RuleFor(x => x.Colours).NotEmpty().When(x => x.Colours is not null);  // it *is* null

There is no way, from inside the handler or a validator, to tell "unparseable value supplied" apart from "parameter omitted". The information is lost in the binder.

Expected behaviour

A collection query string parameter whose element fails to parse should fail the request with 400 Bad Request, consistent with the scalar behaviour introduced by the fix for #3372.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions