reactiveui/refit · error · ArgumentException
HeaderCollection parameter of type {parameterArray[i].Parame
Error message
HeaderCollection parameter of type {parameterArray[i].ParameterType.Name} is not assignable from IDictionary<string, string> What it means
A parameter marked as a header collection must accept IDictionary<string,string>, because Refit assigns header collections via that interface (the comment notes IDictionary is chosen to enforce unique keys). If the parameter type is not assignable from IDictionary<string,string> (e.g. a List, an array, a custom type without that interface), this throws.
Source
Thrown at src/Refit.Reflection/RestMethodInfoInternal.AttributeReading.cs:129
/// <exception cref="ArgumentException">A header collection parameter is not assignable from
/// <c>IDictionary<string, string></c>, or more than one parameter carries
/// <see cref="HeaderCollectionAttribute"/>.</exception>
internal static int GetHeaderCollectionParameterIndex(ParameterInfo[] parameterArray, ParameterAttributeSet[] sets)
{
var headerIndex = -1;
for (var i = 0; i < parameterArray.Length; i++)
{
if (sets[i].HeaderCollection is null)
{
continue;
}
// Opted for IDictionary<string, string> semantics here as opposed to the looser
// IEnumerable<KeyValuePair<string, string>> because IDictionary enforces unique keys.
if (!parameterArray[i].ParameterType.IsAssignableFrom(typeof(IDictionary<string, string>)))
{
throw new ArgumentException(
$"HeaderCollection parameter of type {parameterArray[i].ParameterType.Name} is not assignable from IDictionary<string, string>");
}
// Throw if there is already a HeaderCollection parameter.
if (headerIndex >= 0)
{
throw new ArgumentException("Only one parameter can be a HeaderCollection parameter");
}
headerIndex = i;
}
return headerIndex;
}
/// <summary>Builds the map of parameter indexes to request property keys.</summary>
/// <param name="parameterArray">The array of method parameters.</param>
/// <param name="sets">The classified attribute set for each parameter.</param>View on GitHub (pinned to b455f65ecc)
Solutions
- Declare the header collection parameter as IDictionary<string,string> (or a type assignable from it, e.g. Dictionary<string,string>).
- For multi-valued headers use the supported header binding rather than a custom collection type.
- Confirm the parameter carries the correct header-collection attribute.
Example fix
// before
[Get("/search")] Task SearchAsync([HeaderCollection] List<KeyValuePair<string,string>> h);
// after
[Get("/search")] Task SearchAsync([HeaderCollection] IDictionary<string,string> h); Defensive patterns
Strategy: type-guard
Validate before calling
if (!typeof(T).IsAssignableFrom(typeof(IDictionary<string,string>)))
throw new ArgumentException("Header collection parameter must accept IDictionary<string,string>."); Type guard
static bool IsHeaderCollectionType<T>() => typeof(T).IsAssignableFrom(typeof(IDictionary<string,string>));
Prevention
- Use IDictionary<string,string> (or Dictionary<string,string>) for header-collection parameters.
- Avoid List/array/record types for header collections.
- Review header bindings during code review.
When it happens
Trigger: Declaring a header-collection parameter (a parameter bound to multiple headers) whose declared type does not implement/accept IDictionary<string,string>, such as IEnumerable, a List<>, a record, or a Dictionary with non-string keys.
Common situations: Binding headers to a Dictionary<string,string[]> or a custom multi-value type; using a collection type Refit cannot populate; misreading the header-collection requirement.
Related errors
- Only one parameter can be a HeaderCollection parameter
- [Url] parameter "{param.Name}" must be of type string or Sys
- Method must be defined and have an HTTP Method attribute
- Only one parameter can be an Authorize parameter
- URL {relativePath} has parameter {rawName}, but no method pa
AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13).
Data as JSON: /api/errors/964faf32c476156e.
Report an issue: GitHub.