{"record":{"id":"bc9728255c56e0e4","repo":"microsoft/aspire","slug":"invalidargument","errorCode":"InvalidArgument","errorMessage":"Resource command argument '{name}' must be a string, number, boolean, or null.","messagePattern":"Resource command argument '(.+?)' must be a string, number, boolean, or null\\.","errorType":"http","errorClass":"RpcException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/Dashboard/DashboardService.cs","lineNumber":473,"sourceCode":"\n        var values = new Dictionary<string, string?>(StringComparers.InteractionInputName);\n        foreach (var field in arguments)\n        {\n            values[field.Key] = ConvertArgumentValue(field.Key, field.Value);\n        }\n\n        return values;\n    }\n\n    private static string? ConvertArgumentValue(string name, Value value)\n    {\n        return value.KindCase switch\n        {\n            Value.KindOneofCase.StringValue => value.StringValue,\n            Value.KindOneofCase.NumberValue => value.NumberValue.ToString(\"R\", CultureInfo.InvariantCulture),\n            Value.KindOneofCase.BoolValue => value.BoolValue ? \"true\" : \"false\",\n            Value.KindOneofCase.NullValue => null,\n            _ => throw new RpcException(new Status(StatusCode.InvalidArgument, $\"Resource command argument '{name}' must be a string, number, boolean, or null.\"))\n        };\n    }\n\n    private async Task ExecuteAsync(Func<CancellationToken, Task> execute, ServerCallContext serverCallContext)\n    {\n        using var cts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping, serverCallContext.CancellationToken);\n\n        try\n        {\n            await execute(cts.Token).ConfigureAwait(false);\n        }\n        catch (OperationCanceledException) when (cts.Token.IsCancellationRequested)\n        {\n            // Ignore cancellation and just return.\n        }\n        catch (IOException) when (cts.Token.IsCancellationRequested)\n        {\n            // Ignore cancellation and just return. Cancelled writes throw IOException.","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/Dashboard/DashboardService.cs#L455-L491","documentation":"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.","triggerScenarios":"Calling the ExecuteResourceCommand gRPC with a CommandValues entry whose Value is a StructValue or ListValue (nested object/array), or leaving the oneof unset.","commonSituations":"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.","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."],"exampleFix":"// before\nvar value = new Value { StructValue = new Struct { Fields = { [\"items\"] = new Value { ListValue = new ListValue { Values = { new Value { StringValue = \"a\" } } } } } } };\n// after\nvar value = new Value { StringValue = \"a\" }; // one scalar per argument; serialize lists to a JSON string if needed","handlingStrategy":"validation","validationCode":"bool IsValidArgument(Value v) => v is { KindCase: Value.KindOneofCase.StringValue or Value.KindOneofCase.NumberValue or Value.KindOneofCase.BoolValue or Value.KindOneofCase.NullValue };","typeGuard":"bool IsScalarValue(Value v) => v.KindCase is Value.KindOneofCase.StringValue or Value.KindOneofCase.NumberValue or Value.KindOneofCase.BoolValue or Value.KindOneofCase.NullValue;","tryCatchPattern":"try { await client.ExecuteCommandAsync(cmd); } catch (RpcException ex) when (ex.StatusCode == StatusCode.InvalidArgument) { logger.LogError(\"Command argument rejected: {Detail}\", ex.Status.Detail); }","preventionTips":["Send only scalars (string/number/bool/null) as command arguments","Serialize nested data to a JSON string","Validate payload kinds before invoking commands"],"tags":["grpc","arguments","validation","dashboard"],"backgroundTag":"invalid-argument-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}