HangfireIO/Hangfire · error · JobPerformanceException

An exception occurred during performance of the job.

Error message

An exception occurred during performance of the job.

What it means

Thrown by CoreBackgroundJobPerformer.HandleJobPerformanceException as a JobPerformanceException wrapping any non-cancellation, non-abort exception raised while executing the job method. Hangfire wraps user exceptions to preserve a shallow stack trace and to mark the job failed. The original exception is the InnerException.

Solutions

  1. Inspect InnerException of the JobPerformanceException to find the real cause and fix the job code.
  2. Add try/catch inside the job method to handle expected exceptions and avoid polluting the failed-jobs list.
  3. Configure AutomaticRetryAttribute to retry transient failures and FailedState thresholds appropriately.

Example fix

// before
public void Run()
{
    var data = _repo.Get(id); // may throw
    Process(data.Value);
}

// after
public void Run()
{
    try
    {
        var data = _repo.Get(id);
        Process(data.Value);
    }
    catch (NotFoundException ex)
    {
        _logger.Warn(ex, "item not found, skipping");
    }
}
Defensive patterns

Strategy: try-catch

Try / catch

// In the job method, handle expected exceptions
public void Run()
{
    try { /* work */ }
    catch (TransientException) { throw; } // let Hangfire retry
    catch (BusinessException ex) { _logger.Warn(ex, "skipped"); }
}

Prevention

When it happens

Trigger: The job method (or an async Task it returns) throws any exception that is not a JobAbortedException or a relevant OperationCanceledException. The performer catches it and rethrows wrapped.

Common situations: The job method throws due to a bug, null reference, business-rule violation, network error, DB constraint, etc. Any unhandled exception in the job body surfaces this way.

Related errors


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

Appendix: source

Thrown at src/Hangfire.Core/Server/CoreBackgroundJobPerformer.cs:105

            {
                // OperationCanceledException exception is thrown because 
                // ServerJobCancellationWatcher has detected the job was aborted.
                throw new JobAbortedException();
            }

            if (exception is OperationCanceledException && cancellationToken.ShutdownToken.IsCancellationRequested)
            {
                // OperationCanceledException exceptions are treated differently from
                // others, when ShutdownToken's cancellation was requested, to notify
                // a worker that job performance was aborted by a shutdown request,
                // and a job identifier should BE re-queued.
                ExceptionDispatchInfo.Capture(exception).Throw();
                throw exception;
            }

            // Other exceptions are wrapped with JobPerformanceException to preserve a
            // shallow stack trace without Hangfire methods.
            throw new JobPerformanceException(
                "An exception occurred during performance of the job.",
                exception, job?.Id);
        }

        private object InvokeMethod(PerformContext context, object instance, object[] arguments)
        {
            if (context.BackgroundJob.Job == null) return null;

            try
            {
                var methodInfo = context.BackgroundJob.Job.Method;
                var method = new BackgroundJobMethod(methodInfo, instance, arguments);
                var returnType = methodInfo.ReturnType;

                if (returnType.IsTaskLike(out var getTaskFunc))
                {
                    if (_taskScheduler != null)
                    {

View on GitHub (pinned to c236dd0f93)