louthy/language-ext · error · Exception
Bug in MonadLaw or Monad.unsafeRecur. Contact language-ext…
Error message
Bug in MonadLaw or Monad.unsafeRecur. Contact language-ext maintainer via the repo.
What it means
Monad.Laws.recurIsSameAsBind validates that Monad.recur and Monad.unsafeRecur produce identical results; if they differ, this internal invariant is broken and the library throws asking the user to report it to the language-ext maintainer. It indicates a bug in the monad's Recur/unsafeRecur trait implementation, not user data.
Solutions
- Review and fix the F.Recur/unsafeRecur implementation so unsafeRecur matches recur's observable result
- Report the bug with a repro to the language-ext GitHub repo as the message instructs
- Bypass unsafeRecur in user code and use recur only until the bug is fixed
Example fix
// before static K<F, S, A> unsafeRecur<S, A>((S, A) state, Func<(S, A), K<F, (S, A)>> f) => bind(f(state), s => s.Item1 < 0 ? pure(s) : unsafeRecur(s, f)); // diverges from recur semantics // after // implement unsafeRecur exactly as recur but without the safety check, preserving result equality: same bind recursion, no early exit
Defensive patterns
Strategy: try-catch
Validate before calling
// run the law validation in tests: MonadLaws.validate(monadInstance, examples) before shipping
Try / catch
try { laws.Validate(); }
catch (Exception ex) when (ex.Message.StartsWith("Bug in MonadLaw")) { reportToMaintainer(ex); } Prevention
- Run Monad law validations in unit tests for custom monads
- Implement unsafeRecur to mirror recur exactly (minus safety checks)
- Track language-ext releases for Recur bug fixes
When it happens
Trigger: Running the Monad law-validation suite (via validate) on a monad F whose Recur/unsafeRecur trait methods are implemented inconsistently, so recur(...) != unsafeRecur(...).
Common situations: Writing a custom monad trait implementation with a faulty unsafeRecur (e.g. skipping the recur-loop protection or short-circuiting differently), then running the built-in law checks.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Option is not in a Some state
- Ord attribute should have a struct type that derives from…
- Hashable attribute should have a struct type that derives…
- Don't use Equals - use either RecordType
- Don't use Equals - use either RecordType
AI-assisted analysis of louthy/language-ext@2f0e362824 (2026-09-15).
Data as JSON: /api/errors/18c93fa8e9c22b60.
Report an issue: GitHub.
Appendix: source
Thrown at LanguageExt.Core/Traits/Monads/Monad/Monad.Laws.cs:64
{
equals ??= (fa, fb) => fa.Equals(fb);
return ApplicativeLaw<F>.validate(equals) >>>
leftIdentityLaw(equals) >>>
rightIdentityLaw(equals) >>>
associativityLaw(equals) >>>
recurIsSameAsBind(equals);
}
public static Validation<Error, Unit> recurIsSameAsBind(Func<K<F, int>, K<F, int>, bool>? equals = null)
{
var example = Seq(1, 2, 3, 4, 5, 6, 7, 8, 9);
var result1 = Monad.recur((0, example), rec);
var result2 = Monad.unsafeRecur((0, example), rec);
var result3 = bind(example);
equals ??= (fa, fb) => fa.Equals(fb);
if(!equals(result1, result2)) throw new Exception("Bug in MonadLaw or Monad.unsafeRecur. Contact language-ext maintainer via the repo.");
if (!equals(result1, result3))
{
return Validation.Fail<Error, Unit>(
Error.New($"Monad trait implementation for {typeof(F).Name}.Recur gives a different " +
$"result to the equivalent recursive {typeof(F).Name}.Bind. This suggests " +
$"an implementation bug, most likely in {typeof(F).Name}.Recur, but possibly " +
$"in {typeof(F).Name}.Bind."));
}
return Validation.Success<Error, Unit>(unit);
K<F, Next<(int Total, Seq<int> Values), int>> rec((int Total, Seq<int> Values) pair) =>
pair.Values switch
{
[] => F.Pure(Next.Done<(int, Seq<int>), int>(pair.Total)),
var (x, xs) => F.Pure(Next.Loop<(int, Seq<int>), int>((pair.Total + x, xs)))
};
View on GitHub (pinned to 2f0e362824)