{"record":{"id":"f7335fcb8f714b9c","repo":"dotnet/orleans","slug":"invalid-nameof-adonetgrainstorageoptions-values-f7335f","errorCode":null,"errorMessage":"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} {name}. {nameof(options.HashPicker)} is required.","messagePattern":"Invalid (.+?) values for (.+?) (.+?)\\. (.+?) is required\\.","errorType":"validation","errorClass":"OrleansConfigurationException","httpStatus":null,"severity":"error","filePath":"src/AdoNet/Orleans.Persistence.AdoNet/Options/AdoNetGrainStorageOptions.cs","lineNumber":107,"sourceCode":"            this.name = name;\n        }\n\n        /// <inheritdoc cref=\"IConfigurationValidator\"/>\n        public void ValidateConfiguration()\n        {\n            if (string.IsNullOrWhiteSpace(this.options.Invariant))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} \\\"{name}\\\". {nameof(options.Invariant)} is required.\");\n            }\n\n            if (string.IsNullOrWhiteSpace(this.options.ConnectionString) == (this.options.DataSource is null))\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} \\\"{name}\\\". Configure exactly one of {nameof(options.ConnectionString)} or {nameof(options.DataSource)}.\");\n            }\n\n            if (this.options.HashPicker == null)\n            {\n                throw new OrleansConfigurationException($\"Invalid {nameof(AdoNetGrainStorageOptions)} values for {nameof(AdoNetGrainStorage)} {name}. {nameof(options.HashPicker)} is required.\");\n            }\n        }\n    }\n\n    /// <summary>\n    /// Provides default configuration HashPicker for AdoNetGrainStorageOptions.\n    /// </summary>\n    public class DefaultAdoNetGrainStorageOptionsHashPickerConfigurator : IPostConfigureOptions<AdoNetGrainStorageOptions>\n    {\n        public void PostConfigure(string? name, AdoNetGrainStorageOptions options)\n        {\n            // preserving explicitly configured HashPicker\n            if (options.HashPicker != null)\n                return;\n\n            // set default IHashPicker if not configured yet\n            options.HashPicker = new StorageHasherPicker(new[] { new OrleansDefaultHasher() });\n        }","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/AdoNet/Orleans.Persistence.AdoNet/Options/AdoNetGrainStorageOptions.cs#L89-L125","documentation":"Thrown by the AdoNetGrainStorageOptionsValidator when HashPicker is null. Normally DefaultAdoNetGrainStorageOptionsHashPickerConfigurator (an IPostConfigureOptions) supplies a default StorageHasherPicker at startup, so this fires only when that post-configure did not run — i.e., the grain storage was not registered through the proper AddAdoNetGrainStorage extension that wires the post-configurator, or HashPicker was explicitly nulled.","triggerScenarios":"ValidateConfiguration() runs with options.HashPicker == null because DefaultAdoNetGrainStorageOptionsHashPickerConfigurator never executed. Happens when AdoNetGrainStorageOptions is constructed and validated manually, or storage is registered via a low-level path that skips AddAdoNetGrainStorage.","commonSituations":"Manually new-ing up AdoNetGrainStorageOptions and its validator for testing; registering storage without the extension method that adds the post-configure; explicitly setting HashPicker = null after construction.","solutions":["Register storage through AddAdoNetGrainStorage so DefaultAdoNetGrainStorageOptionsHashPickerConfigurator runs and sets the default HashPicker.","Set options.HashPicker = new StorageHasherPicker(new[] { new OrleansDefaultHasher() }) manually if validating outside the host.","Call options.UseOrleans3CompatibleHasher() if you need v3-compatible hashing, which also sets HashPicker."],"exampleFix":"// before (manual/test path)\nvar options = new AdoNetGrainStorageOptions { /* ... */ };\nnew AdoNetGrainStorageOptionsValidator(options, \"x\").ValidateConfiguration(); // HashPicker null -> error\n\n// after\noptions.HashPicker = new StorageHasherPicker(new[] { new OrleansDefaultHasher() });\nnew AdoNetGrainStorageOptionsValidator(options, \"x\").ValidateConfiguration();","handlingStrategy":"validation","validationCode":"static void CheckHashPicker(AdoNetGrainStorageOptions o)\n{\n    if (o.HashPicker is null)\n        throw new InvalidOperationException(\"HashPicker is null; register storage via AddAdoNetGrainStorage or set HashPicker manually.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always register grain storage through AddAdoNetGrainStorage so the post-configure sets the default HashPicker.","In unit tests that construct options directly, set HashPicker (or call UseOrleans3CompatibleHasher) before validating.","Do not null HashPicker after construction."],"tags":["configuration","adonet","grain-storage","hash-picker","dependency-injection","startup-validation"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}