HangfireIO/Hangfire · error · InvalidEnumArgumentException
compatibilityLevel
Error message
compatibilityLevel
What it means
SetDataCompatibilityLevel validates the compatibilityLevel argument with Enum.IsDefined and throws InvalidEnumArgumentException(nameof(compatibilityLevel), (int)compatibilityLevel, typeof(CompatibilityLevel)) at GlobalConfiguration.cs:65 (on non-NETSTANDARD1_3 targets). The CompatibilityLevel enum only defines Version_110, Version_170, Version_180, so any other integer value is rejected.
Source
Thrown at src/Hangfire.Core/GlobalConfiguration.cs:65
return CompatibilityLevel >= level;
}
internal GlobalConfiguration()
{
}
}
public static class CompatibilityLevelExtensions
{
public static IGlobalConfiguration SetDataCompatibilityLevel(
[NotNull] this IGlobalConfiguration configuration,
CompatibilityLevel compatibilityLevel)
{
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
#if !NETSTANDARD1_3
if (!Enum.IsDefined(typeof(CompatibilityLevel), compatibilityLevel))
throw new InvalidEnumArgumentException(nameof(compatibilityLevel), (int) compatibilityLevel,
typeof(CompatibilityLevel));
#endif
GlobalConfiguration.CompatibilityLevel = compatibilityLevel;
return configuration;
}
}
}
View on GitHub (pinned to c236dd0f93)
Solutions
- Validate with Enum.IsDefined(typeof(CompatibilityLevel), value) before calling, and fall back to a known level.
- Use the named enum member (CompatibilityLevel.Version_170) instead of integer casts.
- Bind configuration to the enum type directly so invalid strings fail at config-bind time rather than at runtime.
- Whitelist the allowed values and reject/log anything else during startup.
Example fix
// before
var lvl = (CompatibilityLevel)configSection.Value; // 0 or 999
cfg.SetDataCompatibilityLevel(lvl);
// after
var raw = configSection.Value;
var lvl = Enum.IsDefined(typeof(CompatibilityLevel), raw)
? (CompatibilityLevel)raw
: CompatibilityLevel.Version_170;
cfg.SetDataCompatibilityLevel(lvl); Defensive patterns
Strategy: validation
Validate before calling
if (!Enum.IsDefined(typeof(CompatibilityLevel), value))
{
throw new ArgumentOutOfRangeException(
nameof(value), value, "Unsupported CompatibilityLevel.");
}
configuration.SetDataCompatibilityLevel((CompatibilityLevel)value); Type guard
static bool IsValidLevel(int v) =>
Enum.IsDefined(typeof(CompatibilityLevel), v); Prevention
- Bind config values to the CompatibilityLevel enum, not to int, so invalid text fails at bind time.
- Whitelist Version_110/170/180 and reject the rest at startup.
- Never cast arbitrary ints to the enum without Enum.IsDefined.
- Pin a single compatibility level across all nodes.
When it happens
Trigger: Passing an undefined enum value, e.g. ((CompatibilityLevel)999), or casting an arbitrary int loaded from config straight to CompatibilityLevel and forwarding it. Also when a future/removed enum member from another Hangfire version is round-tripped.
Common situations: Reading the level from appsettings.json as an int and casting without validation; typos like Version_150; mixing Hangfire versions where the enum members differ; default(int) (0) passed because the value was never set.
Related errors
AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13).
Data as JSON: /api/errors/9abbc51289d26f42.
Report an issue: GitHub.