{"record":{"id":"e284761ecbb99930","repo":"dotnet/yarp","slug":"query-parameter-values-must-not-be-empty","errorCode":null,"errorMessage":"Query parameter values must not be empty.","messagePattern":"Query parameter values must not be empty\\.","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/ReverseProxy/Routing/QueryParameterMatcher.cs","lineNumber":33,"sourceCode":"{\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.\n    /// </summary>\n    public string Name { get; }\n\n    /// <summary>\n    /// Returns a read-only collection of acceptable query parameter values used during routing.\n    /// At least one value is required unless <see cref=\"Mode\"/> is set to <see cref=\"QueryParameterMatchMode.Exists\"/>.\n    /// </summary>\n    public string[] Values { get; }","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/ReverseProxy/Routing/QueryParameterMatcher.cs#L15-L51","documentation":"Thrown by the QueryParameterMatcher constructor when `values` is non-null but contains a null or empty string element (`values.Any(string.IsNullOrEmpty)`). Thrown as ArgumentNullException on the `values` parameter; only reachable for non-Exists modes (Exists with values trips the earlier check).","triggerScenarios":"Calling `new QueryParameterMatcher(name, values, mode, ...)` where `values` includes a null or empty element and mode is a value-matching mode.","commonSituations":"Config with `\"values\": [\"\"]` or `[null]`. Splitting a query template string that yields empty segments. Unsanitized user input feeding the matcher.","solutions":["Strip empty/null entries before construction using `Where(v => !string.IsNullOrEmpty(v))`.","Correct the config to remove blank value tokens.","Validate query-match config blocks for blank values during route validation."],"exampleFix":"// before\nnew QueryParameterMatcher(\"t\", new[] { \"\", \"x\" }, QueryParameterMatchMode.Prefix, false);\n// after\nnew QueryParameterMatcher(\"t\", new[] { \"x\" }, QueryParameterMatchMode.Prefix, false);","handlingStrategy":"validation","validationCode":"values = values?.Where(v => !string.IsNullOrEmpty(v)).ToList();","typeGuard":"static bool HasNoBlankQueryValues(IReadOnlyList<string>? values) =>\n    values is null || values.All(v => !string.IsNullOrEmpty(v));","tryCatchPattern":null,"preventionTips":["Filter empty entries out of value lists before constructing matchers.","Reject blank query-value tokens in config validation.","Use StringSplitOptions.RemoveEmptyEntries when splitting."],"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"}