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
- Inspect the stored JSON for the failing job/state and confirm the "e" property exists and is non-null.
- Align Hangfire versions across all producers/consumers (worker, server, dashboard) so the serialized shape matches.
- Set CompatibilityLevel to the same value everywhere via SetDataCompatibilityLevel so serialization rules agree.
- Delete or expire the corrupt state and let Hangfire re-serialize it; enable job expiration to flush stale records.
- 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
- Keep all Hangfire nodes on the same version and compatibility level so serialized shapes agree.
- Do not strip or rename the 'e' property with custom JsonSerializerSettings.
- Periodically expire/clean job state so corrupt records age out.
- Validate stored JSON shapes in integration tests after upgrades.
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.