HangfireIO/Hangfire · error · ArgumentNullException

type

Error message

type

What it means

ExceptionInfo is deserialized by Newtonsoft.Json via its [JsonConstructor], which requires the type (JSON property "e") to be non-null — otherwise it throws ArgumentNullException(nameof(type)) at ExceptionInfo.cs:43. The type string is the only mandatory field; Message ("m") and InnerException ("i") are optional and ignored when null.

Source

Thrown at src/Hangfire.Core/ExceptionInfo.cs:43

    public sealed class ExceptionInfo
    {
        public ExceptionInfo([NotNull] Exception exception)
        {
            if (exception == null) throw new ArgumentNullException(nameof(exception));

            Message = exception.Message;
            Type = TypeHelper.CurrentTypeSerializer(exception.GetType());

            if (exception.InnerException != null)
            {
                InnerException = new ExceptionInfo(exception.InnerException);
            }
        }

        [JsonConstructor]
        public ExceptionInfo([NotNull] string type, [CanBeNull] string message, [CanBeNull] ExceptionInfo innerException)
        {
            Type = type ?? throw new ArgumentNullException(nameof(type));
            Message = message;
            InnerException = innerException;
        }

        [NotNull]
        [JsonProperty("e")]
        public string Type { get; }

        [CanBeNull]
        [JsonProperty("m", NullValueHandling = NullValueHandling.Ignore)]
        public string Message { get; }

        [CanBeNull]
        [JsonProperty("i", NullValueHandling = NullValueHandling.Ignore)]
        public ExceptionInfo InnerException { get; }

        public override string ToString()
        {

View on GitHub (pinned to c236dd0f93)

Solutions

  1. Inspect the stored JSON for the failing job/state and confirm the "e" property exists and is non-null.
  2. Align Hangfire versions across all producers/consumers (worker, server, dashboard) so the serialized shape matches.
  3. Set CompatibilityLevel to the same value everywhere via SetDataCompatibilityLevel so serialization rules agree.
  4. Delete or expire the corrupt state and let Hangfire re-serialize it; enable job expiration to flush stale records.
  5. If you provide custom JsonSerializerSettings, ensure they do not strip or rename the "e" property.

Example fix

// before
var info = JsonConvert.DeserializeObject<ExceptionInfo>(corruptJson);
// after
var token = JObject.Parse(json)["e"];
var info = token != null && token.Type != JTokenType.Null
    ? JsonConvert.DeserializeObject<ExceptionInfo>(json)
    : null;
Defensive patterns

Strategy: validation

Validate before calling

// before deserializing into ExceptionInfo
var obj = JObject.Parse(json);
var typeToken = obj["e"];
if (typeToken == null || typeToken.Type == JTokenType.Null)
{
    throw new InvalidDataException("ExceptionInfo JSON is missing required 'e' (type) field.");
}
var info = obj.ToObject<ExceptionInfo>();

Type guard

static bool HasExceptionType(string json)
{
    var t = JObject.Parse(json)["e"];
    return t != null && t.Type != JTokenType.Null;
}

Try / catch

try
{
    var info = JsonConvert.DeserializeObject<ExceptionInfo>(json);
}
catch (ArgumentNullException ex) when (ex.ParamName == "type")
{
    // corrupt/partial state: log and skip
    _log.Warn("Skipping ExceptionInfo with missing 'e' field.");
}

Prevention

When it happens

Trigger: Deserializing JSON into ExceptionInfo where the "e" property is absent, explicitly null, or empty. Happens when reading corrupt or partial job-state JSON from storage, or when JSON produced by an older/newer Hangfire version omits "e".

Common situations: Corrupted persisted job state in the storage backend, a schema/serialization mismatch after a Hangfire upgrade or after toggling compatibility level, or a custom serialization settings override that drops the "e" token.

Related errors


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