reactiveui/refit · error · ArgumentException
targetInterface must be an Interface
Error message
targetInterface must be an Interface
What it means
The RequestBuilder constructor requires the type it builds requests for to be a .NET interface. The check `refitInterfaceType?.GetTypeInfo().IsInterface != true` covers both 'not an interface' and 'null', so passing a concrete class, struct, record, or null all throw ArgumentException. Refit generates a proxy from the interface's method metadata, so a non-interface type has nothing to proxy.
Source
Thrown at src/Refit.Reflection/RequestBuilderImplementation.cs:71
/// <summary>The shared route prefix declared by the client interface's <see cref="PathPrefixAttribute"/>, or an empty string when none is present.</summary>
private readonly string _clientPathPrefix;
/// <summary>Initializes a new instance of the <see cref="RequestBuilderImplementation"/> class for the given interface type.</summary>
/// <param name="refitInterfaceType">The Refit interface type to build requests for.</param>
/// <param name="refitSettings">The settings to use, or null for defaults.</param>
/// <exception cref="ArgumentException"><paramref name="refitInterfaceType"/> is null or is not an interface type.</exception>
[RequiresUnreferencedCode("Building requests from reflected interface methods requires interface and request object metadata to be available at runtime.")]
internal RequestBuilderImplementation(
[DynamicallyAccessedMembers(
DynamicallyAccessedMemberTypes.Interfaces
| DynamicallyAccessedMemberTypes.PublicMethods
| DynamicallyAccessedMemberTypes.NonPublicMethods)]
Type refitInterfaceType,
RefitSettings? refitSettings = null)
{
if (refitInterfaceType?.GetTypeInfo().IsInterface != true)
{
throw new ArgumentException("targetInterface must be an Interface");
}
var targetInterfaceInheritedInterfaces = refitInterfaceType.GetInterfaces();
_settings = refitSettings ?? new RefitSettings();
_serializer = _settings.ContentSerializer;
_interfaceGenericHttpMethods =
new();
TargetType = refitInterfaceType;
// The client interface's [PathPrefix] applies to every method it exposes, including methods inherited from
// base interfaces. A base interface's own prefix is ignored here (it applies only when that base is itself the
// client type), so the prefix is read once from the target interface rather than per declaring interface.
_clientPathPrefix = refitInterfaceType.GetCustomAttribute<PathPrefixAttribute>()?.Prefix ?? string.Empty;
var dict = new Dictionary<string, List<RestMethodInfoInternal>>(StringComparer.Ordinal);
View on GitHub (pinned to b455f65ecc)
Solutions
- Define the API contract as an interface decorated with Refit HTTP attributes and register that interface.
- If using RestService.For(typeof(...)), guard that typeof(T).IsInterface before the call.
- Search for AddRefitClient<>/RestService.For<> usages and confirm every T is an interface.
Example fix
// before
public class GithubClient { /* class, not interface */ }
var c = RestService.For<GithubClient>("https://api.github.com");
// after
public interface IGithubClient {
[Get("/users/{user}")] Task<User> GetUserAsync(string user);
}
var c = RestService.For<IGithubClient>("https://api.github.com"); Defensive patterns
Strategy: type-guard
Validate before calling
if (!typeof(T).IsInterface)
throw new ArgumentException($"{typeof(T)} is not an interface; Refit requires an interface."); Type guard
static bool IsRefitInterface<T>() => typeof(T).IsInterface;
Prevention
- Register only interfaces with AddRefitClient<T>/RestService.For<T>.
- Add a compile-time or startup assertion that every registered T is an interface.
- Keep API contracts as interfaces distinct from implementation/DTO classes.
When it happens
Trigger: Calling RestService.For<T>() / RequestBuilder.ForType<T>() / AddRefitClient<T>() with T being a class, struct, or open generic class instead of an interface; or passing null/Type.GetType(...) that resolved to a non-interface.
Common situations: Accidentally registering a concrete client class with AddRefitClient<MyApiClient>(); pointing RestService.For at a shared DTO/model class; refactor that changed an interface to a class but kept the Refit wiring.
Related errors
- Sequence contains more than one matching element
- Sequence contains no matching element
- Method must be defined and have an HTTP Method attribute
- MethodName exists more than once, 'parameterTypes' mut be de
- No suitable Method found...
AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13).
Data as JSON: /api/errors/080e51dda9ef6ef1.
Report an issue: GitHub.