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

  1. Define the API contract as an interface decorated with Refit HTTP attributes and register that interface.
  2. If using RestService.For(typeof(...)), guard that typeof(T).IsInterface before the call.
  3. 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

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


AI-assisted analysis of reactiveui/refit@b455f65ecc (2026-08-13). Data as JSON: /api/errors/080e51dda9ef6ef1. Report an issue: GitHub.