{"record":{"id":"080e51dda9ef6ef1","repo":"reactiveui/refit","slug":"targetinterface-must-be-an-interface","errorCode":null,"errorMessage":"targetInterface must be an Interface","messagePattern":"targetInterface must be an Interface","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Refit.Reflection/RequestBuilderImplementation.cs","lineNumber":71,"sourceCode":"    /// <summary>The shared route prefix declared by the client interface's <see cref=\"PathPrefixAttribute\"/>, or an empty string when none is present.</summary>\n    private readonly string _clientPathPrefix;\n\n    /// <summary>Initializes a new instance of the <see cref=\"RequestBuilderImplementation\"/> class for the given interface type.</summary>\n    /// <param name=\"refitInterfaceType\">The Refit interface type to build requests for.</param>\n    /// <param name=\"refitSettings\">The settings to use, or null for defaults.</param>\n    /// <exception cref=\"ArgumentException\"><paramref name=\"refitInterfaceType\"/> is null or is not an interface type.</exception>\n    [RequiresUnreferencedCode(\"Building requests from reflected interface methods requires interface and request object metadata to be available at runtime.\")]\n    internal RequestBuilderImplementation(\n        [DynamicallyAccessedMembers(\n            DynamicallyAccessedMemberTypes.Interfaces\n            | DynamicallyAccessedMemberTypes.PublicMethods\n            | DynamicallyAccessedMemberTypes.NonPublicMethods)]\n        Type refitInterfaceType,\n        RefitSettings? refitSettings = null)\n    {\n        if (refitInterfaceType?.GetTypeInfo().IsInterface != true)\n        {\n            throw new ArgumentException(\"targetInterface must be an Interface\");\n        }\n\n        var targetInterfaceInheritedInterfaces = refitInterfaceType.GetInterfaces();\n\n        _settings = refitSettings ?? new RefitSettings();\n        _serializer = _settings.ContentSerializer;\n        _interfaceGenericHttpMethods =\n            new();\n\n        TargetType = refitInterfaceType;\n\n        // The client interface's [PathPrefix] applies to every method it exposes, including methods inherited from\n        // base interfaces. A base interface's own prefix is ignored here (it applies only when that base is itself the\n        // client type), so the prefix is read once from the target interface rather than per declaring interface.\n        _clientPathPrefix = refitInterfaceType.GetCustomAttribute<PathPrefixAttribute>()?.Prefix ?? string.Empty;\n\n        var dict = new Dictionary<string, List<RestMethodInfoInternal>>(StringComparer.Ordinal);\n","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/reactiveui/refit/blob/b455f65ecc4c97d092317e349cb775f9cfc6bcdf/src/Refit.Reflection/RequestBuilderImplementation.cs#L53-L89","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\npublic class GithubClient { /* class, not interface */ }\nvar c = RestService.For<GithubClient>(\"https://api.github.com\");\n\n// after\npublic interface IGithubClient {\n    [Get(\"/users/{user}\")] Task<User> GetUserAsync(string user);\n}\nvar c = RestService.For<IGithubClient>(\"https://api.github.com\");","handlingStrategy":"type-guard","validationCode":"if (!typeof(T).IsInterface)\n    throw new ArgumentException($\"{typeof(T)} is not an interface; Refit requires an interface.\");","typeGuard":"static bool IsRefitInterface<T>() => typeof(T).IsInterface;","tryCatchPattern":null,"preventionTips":["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."],"tags":["refit","interface","reflection","configuration","design-time"],"backgroundTag":null,"analyzedSha":"b455f65ecc4c97d092317e349cb775f9cfc6bcdf","analyzedAt":"2026-08-13T21:20:57.878Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}