Skip to content

Wolverine.HTTP: [AsParameters] query binder silently ignores unparseable values instead of returning 400 #3372

Closed

Description

@outofrange-consulting

What happens

When an [AsParameters] query model has a non-nullable enum (or any value-typed) property with a default initializer, Wolverine's generated query-string binder silently ignores an unparseable value and leaves the property at its initializer. The request then succeeds with the default semantics instead of being rejected.

ASP.NET Core's own minimal-API [AsParameters] binder returns 400 Bad Request for the same input, so the behaviour differs from the framework the attribute is borrowed from.

The practical consequence is that a typo'd query value is indistinguishable from an absent one, so there is no way to reject it — not even downstream. A FluentValidation IsInEnum() rule can't catch it either: the binder never writes an out-of-range value (such as 0) that the validator could see, it just doesn't assign at all.

Repro

using Wolverine;
using Wolverine.Http;

var builder = WebApplication.CreateBuilder(args);
builder.Host.UseWolverine();
var app = builder.Build();
app.MapWolverineEndpoints();
await app.RunAsync();

public enum SortField { Name = 1, Date = 2 }

public sealed record SearchQuery
{
    [FromQuery(Name = "sort-by")]
    public SortField SortBy { get; set; } = SortField.Date;
}

public static class SearchEndpoint
{
    [WolverineGet("/search")]
    public static string Get([AsParameters] SearchQuery query) => query.SortBy.ToString();
}
Request Wolverine ASP.NET Core minimal API
GET /search?sort-by=Name 200 — Name 200 — Name
GET /search?sort-by=bogus 200 — Date 400

The same holds for int / long / Guid properties: ?page-size=abc binds to the initializer rather than failing.

Expected

An unparseable value for a bound query parameter should be reportable. Any of these would resolve it:

  1. return 400 on a failed parse, matching ASP.NET Core's [AsParameters] binder;
  2. make it opt-in (e.g. a WolverineHttpOptions flag) so existing lenient behaviour is preserved by default;
  3. at minimum, record the failure somewhere an endpoint or middleware can observe (e.g. as a binding-problem collection on the HttpContext), so a policy can turn it into a 400.

Environment

  • WolverineFx.Http 6.17.0
  • .NET 10

Activity

  1. jeremydmiller commented on Jul 12, 2026

    @jeremydmiller
    Member

    Agreed this is wrong as it stands — silently keeping the initializer value on an unparseable enum/int/Guid is worse than either strictness or leniency, because not even FluentValidation can see it downstream: by the time validation runs, the value looks legitimate.

    Behavior decision, since matching ASP.NET minimal APIs outright (400 on parse failure) would be a breaking behavior change for existing lenient apps:

    • Now (6.x): an opt-in flag on WolverineHttpOptions (working name RejectUnparseableQueryValues). With it on, a TryParse failure in the generated query binder short-circuits to a 400 with ProblemDetails naming the offending parameter — same contract as minimal APIs.
    • 7.0: the flag's default flips, making strict binding the standard behavior and leniency the opt-out.

    The missing-vs-malformed distinction stays: an absent query value keeps the parameter's initializer in both modes; only a present but unparseable value triggers the 400.

    Implementation is small and scheduled in the current community-issue sweep, along with a "strict binding" section in the [AsParameters] docs.

  2. jeremydmiller commented on Jul 12, 2026

    @jeremydmiller
    Member

    Shipped in Wolverine 6.17.2, now on nuget.org.

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