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.

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)

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.