HangfireIO/Hangfire · error · ArgumentNullException

connectionFactory

Error message

connectionFactory

What it means

The SqlServerStorage constructor received a null connectionFactory argument (a Func<DbConnection>). This is a standard ArgumentNullException guard at the top of the (Func<DbConnection>, SqlServerStorageOptions) constructor.

Source

Thrown at src/Hangfire.SqlServer/SqlServerStorage.cs:143

        /// <summary>
        /// Initializes a new instance of the <see cref="SqlServerStorage"/> class with
        /// a connection factory <see cref="Func{DbConnection}"/> class that will be invoked
        /// to create new database connections for querying the data.
        /// </summary>
        public SqlServerStorage([NotNull] Func<DbConnection> connectionFactory)
            : this(connectionFactory, new SqlServerStorageOptions())
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SqlServerStorage"/> class with
        /// a connection factory <see cref="Func{DbConnection}"/> class that will be invoked
        /// to create new database connections for querying the data.
        /// </summary>
        public SqlServerStorage([NotNull] Func<DbConnection> connectionFactory, [NotNull] SqlServerStorageOptions options)
        {
            if (connectionFactory == null) throw new ArgumentNullException(nameof(connectionFactory));
            if (options == null) throw new ArgumentNullException(nameof(options));

            _connectionFactory = connectionFactory;
            _options = options;

            Initialize();
        }

        public virtual PersistentJobQueueProviderCollection QueueProviders { get; private set; }

        public override bool LinearizableReads => true;

        internal string SchemaName => _escapedSchemaName;
        internal int? CommandTimeout => _options.CommandTimeout.HasValue ? (int)_options.CommandTimeout.Value.TotalSeconds : (int?)null;
        internal int? CommandBatchMaxTimeout => _options.CommandBatchMaxTimeout.HasValue ? (int)_options.CommandBatchMaxTimeout.Value.TotalSeconds : (int?)null;
        internal TimeSpan? SlidingInvisibilityTimeout => _options.SlidingInvisibilityTimeout;
        internal SqlServerStorageOptions Options => _options;
        internal SqlServerHeartbeatProcess HeartbeatProcess => _heartbeatProcess;

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Provide a non-null Func<DbConnection> that returns a new, unopened DbConnection each invocation.
  2. If the factory comes from DI, ensure it is registered and resolvable.
  3. Validate with a null check before construction.

Example fix

// before
Func<DbConnection> factory = null; // not initialized
var storage = new SqlServerStorage(factory, options);
// after
Func<DbConnection> factory = () => new SqlConnection(connectionString);
var storage = new SqlServerStorage(factory, options);
Defensive patterns

Strategy: validation

Validate before calling

Func<DbConnection> connectionFactory = /* assignment */;
if (connectionFactory == null)
    throw new InvalidOperationException("connectionFactory delegate must be provided.");

var storage = new SqlServerStorage(connectionFactory, options);

Type guard

static bool IsValidFactory(Func<DbConnection> factory) => factory != null;

Prevention

When it happens

Trigger: Passing null to new SqlServerStorage(connectionFactory, options); a factory variable that was never assigned.

Common situations: DI misconfiguration where the factory delegate resolves to null; refactoring that removes the factory assignment; conditional code paths that skip factory initialization.

Related errors


AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13). Data as JSON: /api/errors/7bee91a1c21396ae. Report an issue: GitHub.