{"record":{"id":"954eb5e704e33915","repo":"dotnet/BenchmarkDotNet","slug":"type-0-no-settable-property-1-found","errorCode":null,"errorMessage":"Type {0}: no settable property {1} found.","messagePattern":"Type (.+?): no settable property (.+?) found\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs","lineNumber":97,"sourceCode":"                flags |= parameter.IsStatic ? BindingFlags.Static : BindingFlags.Instance;\n\n                var paramProperty = targetType.GetProperty(parameter.Name, flags);\n\n                if (paramProperty == null)\n                {\n                    var paramField = targetType.GetField(parameter.Name, flags);\n                    if (paramField == null)\n                        throw new InvalidOperationException(\n                            $\"Type {targetType.FullName}: no property or field {parameter.Name} found.\");\n\n                    var callInstance = paramField.IsStatic ? null : instance;\n                    paramField.SetValue(callInstance, parameter.Value);\n                }\n                else\n                {\n                    var setter = paramProperty.GetSetMethod();\n                    if (setter == null)\n                        throw new InvalidOperationException(\n                            $\"Type {targetType.FullName}: no settable property {parameter.Name} found.\");\n\n                    var callInstance = setter.IsStatic ? null : instance;\n                    setter.Invoke(callInstance, [parameter.Value]);\n                }\n            }\n\n            // Inject CancellationToken into properties/fields marked with [BenchmarkCancellation]\n            foreach (var property in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))\n            {\n                if (property.PropertyType == typeof(CancellationToken) &&\n                    property.IsDefined(typeof(Attributes.BenchmarkCancellationAttribute), inherit: false))\n                {\n                    var setter = property.GetSetMethod();\n                    if (setter != null)\n                    {\n                        var callInstance = setter.IsStatic ? null : instance;\n                        setter.Invoke(callInstance, [cancellationToken]);","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/dotnet/BenchmarkDotNet/blob/b515068b61ad1c9c9aa938b8ece4af1e7d6d85a3/src/BenchmarkDotNet/Toolchains/InProcess/NoEmit/InProcessNoEmitRunner.cs#L79-L115","documentation":"Thrown by the InProcessNoEmit runner's FillMembers method when injecting [Params] values onto the benchmark class instance via reflection. For each parameter it first looks up a public property with the matching name; if one is found but has no public setter (GetSetMethod() returns null), this InvalidOperationException is raised. This only occurs with the in-process no-emit toolchain (e.g. iOS, WASM, or explicitly selected), because it sets values reflectively rather than via emitted code.","triggerScenarios":"FillMembers iterates benchmarkCase.Parameters.Items and calls targetType.GetProperty(parameter.Name, BindingFlags.Public | Static-or-Instance). When a property is found, it calls paramProperty.GetSetMethod() (the no-arg overload, which returns only a PUBLIC setter). If that returns null, the exception fires. This means: (a) [Params] on a read-only auto-property { get; }, (b) [Params] on a property with a private/protected/internal setter like { get; private set; }, (c) [Params] on an expression-bodied property => ....","commonSituations":"Declaring [Params(1,2,3)] public int Size { get; private set; } (encapsulation habit that breaks no-emit mode). Switching a benchmark from the default emit toolchain to InProcessNoEmitToolchain and discovering readonly params. Running benchmarks on iOS (which forces InProcessNoEmit) where the same benchmark worked on desktop.","solutions":["Add a public setter to the parameter property: change { get; } or { get; private set; } to { get; set; }","Convert the parameter from a property to a public field: public int Size; with [Params] — fields do not need setters and are handled by the separate branch at line 85","If you cannot expose a public setter, switch the job away from the no-emit toolchain to the default emitting toolchain (remove .WithToolchain(InProcessNoEmitToolchain.Default)) so BDN generates setter code instead of using reflection"],"exampleFix":"// before\npublic class Bench\n{\n    [Params(1, 2, 4)]\n    public int Size { get; private set; } // no public setter\n\n    [Benchmark]\n    public void Run() => _ = Size * 2;\n}\n\n// after (option 1: public setter)\npublic class Bench\n{\n    [Params(1, 2, 4)]\n    public int Size { get; set; }\n\n    [Benchmark]\n    public void Run() => _ = Size * 2;\n}\n\n// after (option 2: public field)\npublic class Bench\n{\n    [Params(1, 2, 4)]\n    public int Size;\n\n    [Benchmark]\n    public void Run() => _ = Size * 2;\n}","handlingStrategy":"validation","validationCode":"// Run before BenchmarkRunner.Run to verify every [Params] member has a public setter or is a field.\nusing System.Reflection;\nusing BenchmarkDotNet.Attributes;\n\nstatic List<string> ValidateParams(Type benchmarkType)\n{\n    var problems = new List<string>();\n    foreach (var prop in benchmarkType.GetProperties(\n        BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))\n    {\n        if (!prop.IsDefined(typeof(ParamsAttribute), inherit: true)\n            && !prop.IsDefined(typeof(ParamsAllValuesAttribute), inherit: true)\n            && !prop.IsDefined(typeof(ParamsSourceAttribute), inherit: true))\n            continue;\n\n        if (prop.GetSetMethod() is null)\n            problems.Add($\"{benchmarkType.Name}.{prop.Name}: [Params] property has no public setter; use a field or add '{{ get; set; }}'.\");\n    }\n    return problems;\n}\n\nvar errors = ValidateParams(typeof(MyBench));\nif (errors.Count > 0) throw new InvalidOperationException(string.Join(\"\\n\", errors));","typeGuard":"// Narrow a PropertyInfo to 'has a public setter' before relying on it for [Params] injection.\nstatic bool HasPublicSetter(PropertyInfo p) => p.GetSetMethod(nonPublic: false) is not null;","tryCatchPattern":"// This is a configuration error; catching it is a last resort. Prefer fixing the member.\ntry { BenchmarkRunner.Run<MyBench>(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"no settable property\"))\n{\n    // Log the offending type/property from the message and surface a clear config error.\n    throw new ConfigurationErrorsException($\"[Params] member is not settable in no-emit mode: {ex.Message}\", ex);\n}","preventionTips":["Prefer public fields over properties for [Params] — fields never need setters and work across all toolchains.","If you must use a property, always declare it as { get; set; }, never { get; } or { get; private set; }.","When targeting iOS/WASM/Android (which force InProcessNoEmit), run the validation helper above in a unit test over every benchmark class."],"tags":["reflection","in-process","params","no-emit","toolchain"],"backgroundTag":null,"analyzedSha":"b515068b61ad1c9c9aa938b8ece4af1e7d6d85a3","analyzedAt":"2026-08-13T19:12:24.196Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}