louthy/language-ext · error · ExceptionalException
-2000000007
-2000000007
Error message
The IO monad is not in the monad-transformer stack or MonadIO.LiftIO has not been implemented in the trait implementation for your monad-type. Therefore it's not possible to leverage `MonadIO` lifting functionality. To resolve this, implement `MonadIO.LiftIO`.
What it means
MonadIO.LiftIOMaybe's default trait implementation throws ExceptionalException (code -2000000007) because neither the target monad M nor any monad in its transformer stack implements LiftIO. The library cannot lift IO<A> into M without an explicit implementation somewhere in the stack.
Solutions
- Implement/override MonadIO.LiftIO in your monad's trait implementation
- Insert a transformer (e.g. IOT) into the stack that provides LiftIO
- Avoid LiftIO for that monad; keep IO at the outer edge of your program
Example fix
// before
public static virtual K<M, A> LiftIOMaybe<A>(IO<A> ma) => throw new ExceptionalException(Errors.LiftIONotSupported);
// after
public static K<M, A> LiftIO<A>(IO<A> ma) => // in your MonadIO<M> trait impl
map(ma.Run, x => pure(x)); Defensive patterns
Strategy: try-catch
Validate before calling
// static check: typeof(MonadIO<M>).GetMethod("LiftIO") is overridden before calling LiftIOMaybe Type guard
bool CanLiftIO<M>() => typeof(MonadIO<M>).GetMethod("LiftIO")!.DeclaringType != typeof(MonadIO<M>); Try / catch
try { return LiftIOMaybe(ma); }
catch (ExceptionalException ex) when (ex.Code == Errors.LiftIONotSupported.Code) { /* use non-IO path */ } Prevention
- Implement LiftIO in every custom MonadIO trait
- Keep IOT in transformer stacks that must interact with IO
- Test LiftIO support when introducing new monads
When it happens
Trigger: Calling LiftIOMaybe<A>(IO<A>) on a monad whose trait implementation does not override LiftIO and which contains no MonadIO-implementing transformer.
Common situations: Custom monads without MonadIO support, or using a transformer stack missing the IO-handling layer; common when writing generic code parameterised on M.
Related errors
- -2000000009
- 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/e4187bedc30e54aa.
Report an issue: GitHub.
Appendix: source
Thrown at LanguageExt.Core/Traits/Maybe Traits/MonadIO/MonadIO.Trait.cs:42
/// <summary>
/// Lifts the IO monad into a monad transformer stack.
/// </summary>
/// <remarks>
/// IMPLEMENTATION REQUIRED: If this method isn't overloaded in this monad
/// or any monad in the stack on the way to the inner-monad, then it will throw
/// an exception.
///
/// This isn't ideal, it appears to be the only way to achieve this
/// kind of functionality in C# without resorting to magic.
/// </remarks>
/// <param name="ma">IO computation to lift</param>
/// <typeparam name="A">Bound value type</typeparam>
/// <returns>The outer monad with the IO monad lifted into it</returns>
/// <exception cref="ExceptionalException">If this method isn't overloaded in
/// the inner monad or any monad in the stack on the way to the inner-monad,
/// then it will throw an exception.</exception>
public static virtual K<M, A> LiftIOMaybe<A>(IO<A> ma) =>
throw new ExceptionalException(Errors.LiftIONotSupported);
}
}
View on GitHub (pinned to 2f0e362824)