microsoft/aspire · error · RpcException
InvalidArgument
InvalidArgument
Error message
Resource command argument '{name}' must be a string, number, boolean, or null. What it means
ConvertArgumentValue flattens a protobuf Value for a resource command argument into a string. Only string, number, bool, and null kinds are accepted; struct, list, or unset kinds cause an RpcException with StatusCode.InvalidArgument. The dashboard/client sent a command argument with a JSON type the command model cannot represent.
Solutions
- Send only scalar arguments: strings, numbers, booleans, or null for each command parameter.
- Flatten nested objects/arrays into separate scalar arguments or encode them as a JSON string before invoking the command.
- Log the full command payload and verify each argument's protobuf kind before the call.
- Update dashboard/client and AppHost to matching versions if the payload is produced by shipped tooling.
Example fix
// before
var value = new Value { StructValue = new Struct { Fields = { ["items"] = new Value { ListValue = new ListValue { Values = { new Value { StringValue = "a" } } } } } } };
// after
var value = new Value { StringValue = "a" }; // one scalar per argument; serialize lists to a JSON string if needed Defensive patterns
Strategy: validation
Validate before calling
bool IsValidArgument(Value v) => v is { KindCase: Value.KindOneofCase.StringValue or Value.KindOneofCase.NumberValue or Value.KindOneofCase.BoolValue or Value.KindOneofCase.NullValue }; Type guard
bool IsScalarValue(Value v) => v.KindCase is Value.KindOneofCase.StringValue or Value.KindOneofCase.NumberValue or Value.KindOneofCase.BoolValue or Value.KindOneofCase.NullValue;
Try / catch
try { await client.ExecuteCommandAsync(cmd); } catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument) { logger.LogError("Command argument rejected: {Detail}", ex.Status.Detail); } Prevention
- Send only scalars (string/number/bool/null) as command arguments
- Serialize nested data to a JSON string
- Validate payload kinds before invoking commands
When it happens
Trigger: Calling the ExecuteResourceCommand gRPC with a CommandValues entry whose Value is a StructValue or ListValue (nested object/array), or leaving the oneof unset.
Common situations: A custom dashboard or automation client passes an array or object as a command argument; a UI bug serializes arguments as JSON structures instead of scalars.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Array params contains empty item
- At least one exporting assembly name is required.
- Endpoint option ' ' is configured more than once.
- Endpoint option names cannot be empty.
- Endpoint options cannot contain null values.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/bc9728255c56e0e4.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting/Dashboard/DashboardService.cs:473
var values = new Dictionary<string, string?>(StringComparers.InteractionInputName);
foreach (var field in arguments)
{
values[field.Key] = ConvertArgumentValue(field.Key, field.Value);
}
return values;
}
private static string? ConvertArgumentValue(string name, Value value)
{
return value.KindCase switch
{
Value.KindOneofCase.StringValue => value.StringValue,
Value.KindOneofCase.NumberValue => value.NumberValue.ToString("R", CultureInfo.InvariantCulture),
Value.KindOneofCase.BoolValue => value.BoolValue ? "true" : "false",
Value.KindOneofCase.NullValue => null,
_ => throw new RpcException(new Status(StatusCode.InvalidArgument, $"Resource command argument '{name}' must be a string, number, boolean, or null."))
};
}
private async Task ExecuteAsync(Func<CancellationToken, Task> execute, ServerCallContext serverCallContext)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping, serverCallContext.CancellationToken);
try
{
await execute(cts.Token).ConfigureAwait(false);
}
catch (OperationCanceledException) when (cts.Token.IsCancellationRequested)
{
// Ignore cancellation and just return.
}
catch (IOException) when (cts.Token.IsCancellationRequested)
{
// Ignore cancellation and just return. Cancelled writes throw IOException.View on GitHub (pinned to 25830f84bd)