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

  1. Implement/override MonadIO.LiftIO in your monad's trait implementation
  2. Insert a transformer (e.g. IOT) into the stack that provides LiftIO
  3. 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

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


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)