microsoft/autogen · error · RpcException

INVALID_ARGUMENT

INVALID_ARGUMENT

Error message

Grpc Client ID is required.

What it means

Thrown by GrpcGateway.RegisterAgentTypeAsync when the gRPC call does not carry a 'client-id' metadata header. The gateway identifies each worker by this header, so a registration without it cannot be attributed to any connection. It surfaces to the caller as an RpcException with StatusCode.InvalidArgument.

Source

Thrown at dotnet/src/Microsoft.AutoGen/RuntimeGateway.Grpc/Services/Grpc/GrpcGateway.cs:126

        await connection.ResponseStream.WriteAsync(new Message { Request = request }, cancellationToken).ConfigureAwait(false);
        var response = await completion.Task.WaitAsync(s_agentResponseTimeout);
        response.RequestId = originalRequestId;
        return response;
    }

    /// <summary>
    /// Registers an agent type asynchronously.
    /// </summary>
    /// <param name="request">The register agent type request.</param>
    /// <param name="context">The server call context.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains the register agent type response.</returns>
    public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request, ServerCallContext context, CancellationToken cancellationToken = default)
    {
        try
        {
            var clientId = context.RequestHeaders.Get("client-id")?.Value ??
                throw new RpcException(new Status(StatusCode.InvalidArgument, "Grpc Client ID is required."));

            Func<ValueTask> registerLambda = async () =>
            {
                if (!_workers.TryGetValue(clientId, out var connection))
                {
                    throw new RpcException(new Status(StatusCode.InvalidArgument, $"Grpc Worker Connection not found for ClientId {clientId}. Retry after you call OpenChannel() first."));
                }
                connection.AddSupportedType(request.Type);
                _supportedAgentTypes.GetOrAdd(request.Type, _ => []).Add(connection);

                await _gatewayRegistry.RegisterAgentTypeAsync(request, clientId, _reference).ConfigureAwait(true);
            };

            await InvokeOrDeferRegistrationAction(clientId, registerLambda).ConfigureAwait(true);

            return new RegisterAgentTypeResponse { };
        }
        catch (Exception ex)

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Attach the client-id header to the call: new Metadata { { "client-id", client.ClientId } } and pass it as headers when invoking RegisterAgentTypeAsync.
  2. Verify no client-side interceptor (logging, auth, retry) strips or renames custom metadata entries.
  3. If you use the shipped AutoGen .NET worker runtime, confirm you are on a version whose gateway and client agree on the 'client-id' header name (older builds used different identification schemes).

Example fix

// before
await client.RegisterAgentTypeAsync(new RegisterAgentTypeRequest { Type = "MyAgent" });

// after
var headers = new Metadata { { "client-id", clientId } };
await client.RegisterAgentTypeAsync(new RegisterAgentTypeRequest { Type = "MyAgent" }, headers);
Defensive patterns

Strategy: validation

Validate before calling

// Before making the call, ensure metadata carries the header
var headers = new Metadata();
if (!headers.Any(h => h.Key == "client-id"))
{
    headers.Add("client-id", clientId);
}
if (string.IsNullOrEmpty(headers.GetValue("client-id")?.Value))
    throw new InvalidOperationException("client-id header must be set before RegisterAgentTypeAsync");

Try / catch

try { await client.RegisterAgentTypeAsync(request, headers); }
catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument && ex.Status.Detail.Contains("Client ID is required"))
{
    _logger.LogError("Missing client-id metadata; attaching and retrying once.");
    headers.Add("client-id", clientId);
    await client.RegisterAgentTypeAsync(request, headers);
}

Prevention

When it happens

Trigger: Calling the RegisterAgentType RPC (or the AutoGen worker runtime's agent-type registration flow) without adding a 'client-id' entry to the request headers. The very first line of RegisterAgentTypeAsync reads context.RequestHeaders.Get("client-id") and throws when it is null.

Common situations: Custom worker implementations that build their own gRPC client and forget to attach metadata; SDK version upgrades that changed header names; proxies or interceptors that strip custom metadata; passing the id as part of the request body or message instead of headers.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/23fb483e68352d22. Report an issue: GitHub.