{"record":{"id":"23fb483e68352d22","repo":"microsoft/autogen","slug":"invalid-argument","errorCode":"INVALID_ARGUMENT","errorMessage":"Grpc Client ID is required.","messagePattern":"Grpc Client ID is required\\.","errorType":"exception","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"dotnet/src/Microsoft.AutoGen/RuntimeGateway.Grpc/Services/Grpc/GrpcGateway.cs","lineNumber":126,"sourceCode":"        await connection.ResponseStream.WriteAsync(new Message { Request = request }, cancellationToken).ConfigureAwait(false);\n        var response = await completion.Task.WaitAsync(s_agentResponseTimeout);\n        response.RequestId = originalRequestId;\n        return response;\n    }\n\n    /// <summary>\n    /// Registers an agent type asynchronously.\n    /// </summary>\n    /// <param name=\"request\">The register agent type request.</param>\n    /// <param name=\"context\">The server call context.</param>\n    /// <param name=\"cancellationToken\">The cancellation token.</param>\n    /// <returns>A task that represents the asynchronous operation. The task result contains the register agent type response.</returns>\n    public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request, ServerCallContext context, CancellationToken cancellationToken = default)\n    {\n        try\n        {\n            var clientId = context.RequestHeaders.Get(\"client-id\")?.Value ??\n                throw new RpcException(new Status(StatusCode.InvalidArgument, \"Grpc Client ID is required.\"));\n\n            Func<ValueTask> registerLambda = async () =>\n            {\n                if (!_workers.TryGetValue(clientId, out var connection))\n                {\n                    throw new RpcException(new Status(StatusCode.InvalidArgument, $\"Grpc Worker Connection not found for ClientId {clientId}. Retry after you call OpenChannel() first.\"));\n                }\n                connection.AddSupportedType(request.Type);\n                _supportedAgentTypes.GetOrAdd(request.Type, _ => []).Add(connection);\n\n                await _gatewayRegistry.RegisterAgentTypeAsync(request, clientId, _reference).ConfigureAwait(true);\n            };\n\n            await InvokeOrDeferRegistrationAction(clientId, registerLambda).ConfigureAwait(true);\n\n            return new RegisterAgentTypeResponse { };\n        }\n        catch (Exception ex)","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/dotnet/src/Microsoft.AutoGen/RuntimeGateway.Grpc/Services/Grpc/GrpcGateway.cs#L108-L144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Attach the client-id header to the call: new Metadata { { \"client-id\", client.ClientId } } and pass it as headers when invoking RegisterAgentTypeAsync.","Verify no client-side interceptor (logging, auth, retry) strips or renames custom metadata entries.","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)."],"exampleFix":"// before\nawait client.RegisterAgentTypeAsync(new RegisterAgentTypeRequest { Type = \"MyAgent\" });\n\n// after\nvar headers = new Metadata { { \"client-id\", clientId } };\nawait client.RegisterAgentTypeAsync(new RegisterAgentTypeRequest { Type = \"MyAgent\" }, headers);","handlingStrategy":"validation","validationCode":"// Before making the call, ensure metadata carries the header\nvar headers = new Metadata();\nif (!headers.Any(h => h.Key == \"client-id\"))\n{\n    headers.Add(\"client-id\", clientId);\n}\nif (string.IsNullOrEmpty(headers.GetValue(\"client-id\")?.Value))\n    throw new InvalidOperationException(\"client-id header must be set before RegisterAgentTypeAsync\");","typeGuard":null,"tryCatchPattern":"try { await client.RegisterAgentTypeAsync(request, headers); }\ncatch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument && ex.Status.Detail.Contains(\"Client ID is required\"))\n{\n    _logger.LogError(\"Missing client-id metadata; attaching and retrying once.\");\n    headers.Add(\"client-id\", clientId);\n    await client.RegisterAgentTypeAsync(request, headers);\n}","preventionTips":["Centralize gRPC header construction in one client factory that always attaches client-id.","Add an integration test asserting registration fails with a clear message when the header is absent.","Log (not throw) at the client when client-id is empty before any gateway call."],"tags":["grpc","dotnet","metadata","agent-registration"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}