HangfireIO/Hangfire · error · ArgumentNullException
waitHandle
Error message
waitHandle
What it means
Thrown by the TaskExtensions.WaitOne extension method (internal) when the WaitHandle argument is null. WaitOne combines the handle with a cancellation event in WaitHandle.WaitAny, so a null handle would NRE inside the array.
Source
Thrown at src/Hangfire.Core/Processing/TaskExtensions.cs:34
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Hangfire.Annotations;
using Hangfire.Common;
using Hangfire.Logging;
namespace Hangfire.Processing
{
internal static class TaskExtensions
{
private static readonly Type[] EmptyTypes = Type.EmptyTypes;
private static readonly WaitHandle InvalidWaitHandleInstance = new InvalidWaitHandle();
public static bool WaitOne([NotNull] this WaitHandle waitHandle, TimeSpan timeout, CancellationToken token)
{
if (waitHandle == null) throw new ArgumentNullException(nameof(waitHandle));
if (timeout < Timeout.InfiniteTimeSpan) throw new ArgumentOutOfRangeException(nameof(timeout));
token.ThrowIfCancellationRequested();
using var ev = token.GetCancellationEvent();
var waitHandles = new[] { waitHandle, ev.WaitHandle };
var stopwatch = Stopwatch.StartNew();
var waitResult = WaitHandle.WaitAny(waitHandles, timeout);
stopwatch.Stop();
var timeoutThreshold = TimeSpan.FromMilliseconds(1000);
var elapsedThreshold = TimeSpan.FromMilliseconds(500);
var protectionTime = TimeSpan.FromSeconds(1);
if (waitResult == 0)
{View on GitHub (pinned to c236dd0f93)
Solutions
- Ensure the WaitHandle passed is non-null (the ManualResetEvent/CountdownEvent should always be initialised).
- Add a null check at the call site and fail fast with context if the handle is unexpectedly null.
- If this surfaces in production, treat it as a Hangfire internal-state bug and report it.
Example fix
// before
handle.WaitOne(timeout, token); // handle == null
// after
if (handle == null) throw new InvalidOperationException("Wait handle was not initialized.");
handle.WaitOne(timeout, token); Defensive patterns
Strategy: validation
Validate before calling
if (waitHandle == null) throw new InvalidOperationException("WaitHandle was not initialized.");
return waitHandle.WaitOne(timeout, token); Prevention
- Ensure the owning event (ManualResetEvent/CountdownEvent) is constructed before any wait.
- Do not null out handle fields before all waits complete.
- Treat an unexpected null here as an internal-state defect.
When it happens
Trigger: Calling waitHandle.WaitOne(timeout, token) where waitHandle is null. Reached through BackgroundExecution's delay handling (_stopped.WaitOne) if the underlying event was null — which should not happen in normal operation.
Common situations: A test stub passes a null WaitHandle to exercise the extension; internal state corruption where _stopped was not initialised; a refactor that nulls the handle field prematurely.
Related errors
- All the threads should be non-null and in the ThreadState.Un
- maxConcurrency
- execution
- taskScheduler
- options
AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13).
Data as JSON: /api/errors/51612f4100e5d0ce.
Report an issue: GitHub.