Error: The Delegate RequestDelegate does not take X arguments – Experiences with minimal APIs

When working with .NET minimal APIs, the endpoint definition can be improved by using TypedResults for better OpenAPI documentation. However, this seemingly simple change can lead to confusing compiler errors, such as “Delegate RequestDelegate does not take X arguments.” Even the GitHub Copilot coding agent struggled to resolve these issues automatically.

In this article, we’ll explore why this error occurs, what it means for your API design, and how to resolve it using the generic Results type.

Copilot coding agent results

After GitHub Copilot coding agent created an API for me, with a pull request review I asked to:

  • With the minimal APIs in the EduValidate.Apiservice project, create an endpoints-class and move the minimal APIs code from Program.cs to this file.
  • With minimal APIs, use TypedResults instead of Results

Copilot succeeded doing the first task, but failed with the second one:

✅ Created endpoints class – Moved minimal API code from Program.cs to Endpoints/CodeAnalysisEndpoints.cs

⚠️ TypedResults issue – Discovered that replacing Results with TypedResults causes compilation errors (“Delegate RequestDelegate does not take X arguments”). This appears to be a type inference issue in the minimal API processing. The endpoints work correctly with Results for now.

I had some more tasks to fix, and Copilot fixed all of them with the exception of this one. Many developers encounter this error. Let’s examine why it happens and how to resolve it.

Using Results

A minimal APIs code using the Results class to return results can look like this:

app.MapGet("/api/submission/{submissionId}/analysis", async (
  string submissionId,
  EduValidateDbContext dbContext,
  CancellationToken cancellationToken) =>
{
  // some code

  if (submission == null)
  {
    return Results.NotFound($"Submission {submissionId} not found");
  }

  // some code
  return Results.Ok(analysisResult);
})
.WithName("GetAnalysis")
.WithSummary("Get analysis results for a submission");

In case there’s just only one possible result type, the Results class can easily be replaced with a TypedResults, but with two or more occurrences, this code no longer compiles:

app.MapGet("/api/submission/{submissionId}/analysis", async (
  string submissionId,
  EduValidateDbContext dbContext,
  CancellationToken cancellationToken) =>
{
  // some code

  if (submission == null)
  {
    return TypedResults.NotFound($"Submission {submissionId} not found");
  }

  // some code
  return TypedResults.Ok(analysisResult);
})
.WithName("GetAnalysis")
.WithSummary("Get analysis results for a submission");

The compiler complains with Delegate RequestDelegate does not take 3 arguments.

Why using TypedResults at all? When using TypedResults, the information what can be returned from the API is added to the OpenAPI document, without the need to add attributes for every result type.

What’s the reason for this error?

Why does the RequestDelegate overload match?

The method MapGet is specified with two overloads.

One is the one we would like to use when passing an expression. This method has been added for minimal APIs:

[RequiresDynamicCode("This API may perform reflection on the supplied delegate and its parameters. These types may require generated code and aren't compatible with native AOT applications.")]
[RequiresUnreferencedCode("This API may perform reflection on the supplied delegate and its parameters. These types may be trimmed if not directly referenced.")]
public static RouteHandlerBuilder MapGet(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern, Delegate handler);

This overload existed before minimal APIs have been available. This method receives a RequestDelegate parameter:

public static IEndpointConventionBuilder MapGet(this IEndpointRouteBuilder endpoints, [StringSyntax("Route")] string pattern, RequestDelegate requestDelegate);

The compiler now assumes to use this overload instead of the previous one. However, this overload needs a match with parameters and the return type for the RequestDelegate delegate type. This definition returns a Task, and can only use a HttpContext as parameter.

public delegate Task RequestDelegate(HttpContext context);

When enabling to use the RequestDelegateGenerator (which is used with native AOT, or specifying EnableRequestDelegateGenerator in the project file), the source generator replaces the method with the Delegate parameter to use the method with the RequestDelegate parameter instead, which enables minimal APIs with native AOT.

Using a lambda expression, the compiler checks for all ´returnstatements within the method to resolve the result type. The methods of theResultsclass returnIResult. However, TypedResults.Ok<T>returnsOk<T>, and TypedResults.NotFound<string>returnsNotFound<string>. As the compiler cannot resolve the result type directly, the RequestDelegate` overload is used, which doesn’t match the number of parameters.

All these return types implement the interface IResult. Thus changing the return type to Task<IResult> helps compiling:

app.MapGet("/api/submission/{submissionId}/analysis", async Task<IResult> (
  string submissionId,
  EduValidateDbContext dbContext,
  CancellationToken cancellationToken) =>
{
  // some code

  if (submission == null)
  {
    return TypedResults.NotFound($"Submission {submissionId} not found");
  }

  // some code
  return TypedResults.Ok(analysisResult);
})
.WithName("GetAnalysis")
.WithSummary("Get analysis results for a submission");

However, this is not the fix needed to add the result information to the OpenAPI description.

The fix

This can be fixed by using the generic Results type which allows using 2, 3, 4, or more generic parameters types, and specifying the result types:

app.MapGet("/api/submission/{submissionId}/analysis", async Task<Results<Ok<CodeAnalysisResult>, NotFound<string>>> (
  string submissionId,
  EduValidateDbContext dbContext,
  ILogger<ICodeAnalysisService> logger,
  CancellationToken cancellationToken) =>
{

The results returned is either Ok<CodeAnalysisResult>, or NotFound<string>, wrapped into a Task.

With this change, the information on the return values goes to the OpenAPI description.

The Copilot coding agent is enhanced continuously. It’s also possible to connect him to learn from my own repositories, where I’m sure he would have resolved the issue automatically. Maybe he also learns from reading this article 🙂

Summary

In summary, when building minimal APIs, using the generic Results type with specific result types not only resolves confusing compiler errors but also improves your OpenAPI documentation. This approach ensures your endpoints are both robust and well-documented.

For more information:

Creating APIs is covered in Chapter 2 of my book:

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.