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

  1. Validate with Enum.IsDefined(typeof(CompatibilityLevel), value) before calling, and fall back to a known level.
  2. Use the named enum member (CompatibilityLevel.Version_170) instead of integer casts.
  3. Bind configuration to the enum type directly so invalid strings fail at config-bind time rather than at runtime.
  4. 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

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.