{"record":{"id":"2eec9e7fb62c355e","repo":"dotnet/yarp","slug":"query-parameter-values-must-have-at-least-one-valu","errorCode":null,"errorMessage":"Query parameter values must have at least one value.","messagePattern":"Query parameter values must have at least one value\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Routing/QueryParameterMatcher.cs","lineNumber":25,"sourceCode":"using Yarp.ReverseProxy.Configuration;\n\nnamespace Yarp.ReverseProxy.Routing;\n\n/// <summary>\n/// A request query parameter matcher used during routing.\n/// </summary>\ninternal sealed class QueryParameterMatcher\n{\n    /// <summary>\n    /// Creates a new instance.\n    /// </summary>\n    public QueryParameterMatcher(string name, IReadOnlyList<string>? values, QueryParameterMatchMode mode, bool isCaseSensitive)\n    {\n        ArgumentException.ThrowIfNullOrEmpty(name);\n        if (mode != QueryParameterMatchMode.Exists\n            && (values is null || values.Count == 0))\n        {\n            throw new ArgumentException(\"Query parameter values must have at least one value.\", nameof(values));\n        }\n        if (mode == QueryParameterMatchMode.Exists && values?.Count > 0)\n        {\n            throw new ArgumentException($\"Query parameter values must not be specified when using '{nameof(QueryParameterMatchMode.Exists)}'.\", nameof(values));\n        }\n        if (values is not null && values.Any(string.IsNullOrEmpty))\n        {\n            throw new ArgumentNullException(nameof(values), \"Query parameter values must not be empty.\");\n        }\n\n        Name = name;\n        Values = values?.ToArray() ?? Array.Empty<string>();\n        Mode = mode;\n        Comparison = isCaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;\n    }\n\n    /// <summary>\n    /// Name of the query parameter to look for.","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Routing/QueryParameterMatcher.cs#L7-L43","documentation":"Thrown by the QueryParameterMatcher constructor when the match Mode is anything other than `Exists` (e.g. Exact, Prefix, Contains) and the `values` list is null or empty. Non-existence modes require at least one value to compare the query parameter against.","triggerScenarios":"Constructing `new QueryParameterMatcher(name, values, mode, isCaseSensitive)` with `mode != QueryParameterMatchMode.Exists` and `values` null or zero-length. Reached via YARP route config binding a query-parameter match without values.","commonSituations":"Config sets `mode: Exact` but omits `values`. Copy-paste from an Exists rule without adding values. Generated config that drops the values array when it's a single empty default.","solutions":["Supply at least one value string for non-Exists modes.","If presence-only semantics are intended, switch Mode to `Exists` and omit values.","Validate config: assert `(mode == Exists) || (values?.Count > 0)` before construction."],"exampleFix":"// before\nnew QueryParameterMatcher(\"t\", null, QueryParameterMatchMode.Exact, false);\n// after\nnew QueryParameterMatcher(\"t\", new[] { \"json\" }, QueryParameterMatchMode.Exact, false);","handlingStrategy":"validation","validationCode":"if (mode != QueryParameterMatchMode.Exists && (values is null || values.Count == 0))\n    throw new InvalidOperationException(\"Non-Exists query match requires values.\");","typeGuard":"static bool IsValidQueryMatcherConfig(QueryParameterMatchMode mode, IReadOnlyList<string>? values) =>\n    mode == QueryParameterMatchMode.Exists || (values is not null && values.Count > 0);","tryCatchPattern":null,"preventionTips":["Pair every non-Exists query match with at least one value in config.","Validate config at startup before binding into matchers.","Document that Exists is the only presence-only mode."],"tags":["routing","query-match","argument-validation","yarp"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}