{"record":{"id":"18ef3c354399a646","repo":"dotnet/orleans","slug":"value-cannot-be-null-parameter-selector","errorCode":null,"errorMessage":"Value cannot be null. (Parameter 'selector')","messagePattern":"Value cannot be null\\. \\(Parameter 'selector'\\)","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/AdoNet/Shared/Storage/RelationalStorage.cs","lineNumber":202,"sourceCode":"        ///        return new Information\n        ///        {\n        ///            TABLE_CATALOG = selector.GetValueOrDefault&lt;string&gt;(\"TABLE_CATALOG\"),\n        ///            TABLE_NAME = selector.GetValueOrDefault&lt;string&gt;(\"TABLE_NAME\")\n        ///        }\n        ///}).ConfigureAwait(continueOnCapturedContext: false);\n        /// </code>\n        /// </example>\n        public async Task<IEnumerable<TResult>> ReadAsync<TResult>(string query, Action<IDbCommand>? parameterProvider, Func<IDataRecord, int, CancellationToken, Task<TResult>> selector, CommandBehavior commandBehavior = CommandBehavior.Default, CancellationToken cancellationToken = default)\n        {\n            //If the query is something else that is not acceptable (e.g. an empty string), there will an appropriate database exception.\n            if (query == null)\n            {\n                throw new ArgumentNullException(nameof(query));\n            }\n\n            if (selector == null)\n            {\n                throw new ArgumentNullException(nameof(selector));\n            }\n\n            return (await ExecuteAsync(query, parameterProvider, ExecuteReaderAsync, selector, commandBehavior, cancellationToken).ConfigureAwait(false)).Item1;\n        }\n\n\n        /// <summary>\n        /// Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.\n        /// </summary>\n        /// <param name=\"query\">The query to execute.</param>\n        /// <param name=\"parameterProvider\">Adds parameters to the query. Parameter names must match those defined in the query.</param>\n        /// <param name=\"commandBehavior\">The command behavior that should be used. Defaults to <see cref=\"CommandBehavior.Default\"/>.</param>\n        /// <param name=\"cancellationToken\">The cancellation token. Defaults to <see cref=\"CancellationToken.None\"/>.</param>\n        /// <returns>Affected rows count.</returns>\n        /// <example>This sample shows how to make a hand-tuned database call.\n        /// <code>\n        /// //In contract to reading, execute queries are simpler as they return only\n        /// //the affected rows count if it is available.","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/dotnet/orleans/blob/fca799fa70ecb6ad975224271703ca43221f58de/src/AdoNet/Shared/Storage/RelationalStorage.cs#L184-L220","documentation":"Thrown by RelationalStorage.ReadAsync<TResult> when the selector delegate (Func<IDataRecord, int, CancellationToken, Task<TResult>>) is null. The selector transforms each IDataRecord row into TResult; without it ReadAsync cannot materialize results, so the call is rejected with ArgumentNullException(nameof(selector)). parameterProvider may legitimately be null.","triggerScenarios":"Calling ReadAsync with a null selector, often by omitting an argument, mis-ordering arguments, or passing a method-group that resolved to null.","commonSituations":"Refactors that changed the selector signature so the old reference no longer binds; copy-paste that dropped the selector; using the reflection-based ReadAsync overload by mistake.","solutions":["Supply a non-null selector, e.g. (record, i, ct) => Task.FromResult(new T { ... }).","Use the extension ReadAsync<TResult>(storage, query, selector, parameterProvider) or the reflection overload ReadAsync<TResult>(storage, query, parameters) if you want automatic mapping.","Verify the selector argument is assigned before the call in refactor reviews.","Enable nullable reference types so a null selector is a compile-time warning."],"exampleFix":"// before\nvar rows = await storage.ReadAsync<T>(query, null, null); // selector null -> throws\n\n// after\nvar rows = await storage.ReadAsync<T>(\n    query,\n    cmd => {},\n    (record, i, ct) => Task.FromResult(new T { Id = record.GetValueOrDefault<int>(\"Id\") }));","handlingStrategy":"validation","validationCode":"if (selector is null) throw new ArgumentNullException(nameof(selector));","typeGuard":"static bool HasSelector<TResult>(Func<IDataRecord,int,CancellationToken,Task<TResult>>? s) => s is not null;","tryCatchPattern":"try { await storage.ReadAsync<T>(query, p, selector); }\ncatch (ArgumentNullException ex) when (ex.ParamName == nameof(selector)) { /* supply selector */ }","preventionTips":["Use the reflection-based ReadAsync overload if you want automatic mapping.","Enable nullable reference types to catch null selectors at compile time.","Review selectors after signature refactors."],"tags":["csharp","dotnet","orleans","adonet","argument-validation"],"backgroundTag":null,"analyzedSha":"fca799fa70ecb6ad975224271703ca43221f58de","analyzedAt":"2026-08-13T19:55:57.938Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}