quarkusio/quarkus · error · IllegalStateException

No current Mutiny.Session found - no reactive session was f

Error message

No current Mutiny.Session found
	- no reactive session was found in the Vert.x context and the context was not marked to open a new session lazily
	- a session is opened automatically for JAX-RS resource methods annotated with an HTTP method (@GET, @POST, etc.); inherited annotations are not taken into account
	- you may need to annotate the business method with @Transactional, @WithSession or @WithTransaction

What it means

SessionOperations.getSession must obtain the current Mutiny.Session for a persistence unit from the Vert.x duplicated context. When no reactive session exists in the context and the context was not marked to open a session lazily (no @WithSession/@WithTransaction/@Transactional marker keys), it throws IllegalStateException with a multi-line diagnostic. Reactive sessions are propagated via Vert.x context locals, so Panache operations only work inside a managed reactive context (e.g. JAX-RS resource methods with an HTTP-annotation).

Source

Thrown at extensions/panache/hibernate-reactive-panache-common/runtime/src/main/java/io/quarkus/hibernate/reactive/panache/common/runtime/SessionOperations.java:293

        Context context = vertxContext();
        // First make sure we don't already have an opened stateless session
        Uni<Mutiny.Session> error = checkNoStatelessSession(context, persistenceUnitName);
        if (error != null) {
            return error;
        }
        Optional<OpenedSessionsState.SessionWithKey<Mutiny.Session>> opened = OPENED_SESSIONS_STATE.getOpenedSession(context,
                persistenceUnitName);
        if (opened.isPresent()) {
            return Uni.createFrom().item(opened.get().session());
        } else if (ContextLocals.get(context, SESSION_ON_DEMAND_KEY, null) != null) {
            trackOnDemandSession(context, persistenceUnitName);
            return Uni.createFrom()
                    .item(() -> HibernateReactiveRecorder.getSession(persistenceUnitName, SESSION_ON_DEMAND_KEY));
        } else if (ContextLocals.get(context, TRANSACTIONAL_METHOD_KEY, null) != null) {
            return Uni.createFrom()
                    .item(() -> HibernateReactiveRecorder.getSession(persistenceUnitName, TRANSACTIONAL_METHOD_KEY));
        } else {
            throw new IllegalStateException("No current Mutiny.Session found"
                    + "\n\t- no reactive session was found in the Vert.x context and the context was not marked to open a new session lazily"
                    + "\n\t- a session is opened automatically for JAX-RS resource methods annotated with an HTTP method (@GET, @POST, etc.); inherited annotations are not taken into account"
                    + "\n\t- you may need to annotate the business method with @Transactional, @WithSession or @WithTransaction");
        }
    }

    /**
     * If there is a reactive stateless session stored in the current Vert.x duplicated context then this stateless session is
     * reused.
     * <p>
     * However, if there is no reactive stateless session found then:
     * <ol>
     * <li>if the current vertx duplicated context is marked as "lazy" then a new stateless session is opened and stored it in
     * the
     * context</li>
     * <li>if the current context is marked as transactional then a new stateless session is created via the shared session
     * state</li>
     * <li>otherwise an exception thrown</li>

View on GitHub (pinned to e1c734241f)

Solutions

  1. Annotate the business method with @WithSession (or @WithTransaction) so a session is opened lazily and stored in the Vert.x context.
  2. If the method performs DB work transactionally, add @Transactional (which sets the transactional marker) instead.
  3. For JAX-RS endpoints, ensure the HTTP-verb annotation (@GET/@POST/...) is on the method itself, not only on a superclass, since inherited annotations are not considered.
  4. Capture the Vert.x duplicated context and rerun the work on that context (Vertx.getOrCreateContext().runOnContext(...)) when offloading to other threads.
  5. For schedulers/messaging, wrap the handler with the reactive-session aware API or inject SessionOperations-managed scope via @WithSession.

Example fix

// before
@ApplicationScoped
public class UserService {
    public Uni<User> find(long id) {
        return User.findById(id); // IllegalStateException: no session
    }
}

// after
@ApplicationScoped
public class UserService {
    @WithSession
    public Uni<User> find(long id) {
        return User.findById(id);
    }
}
Defensive patterns

Strategy: validation

Validate before calling

if (Vertx.currentContext() == null || io.vertx.core.Context.isOnWorkerThread()) {
    throw new IllegalStateException("Panache reactive calls require a Vert.x duplicated context; annotate the method with @WithSession/@WithTransaction");
}

Try / catch

try { return User.findById(id); } catch (IllegalStateException e) { if (e.getMessage().startsWith("No current Mutiny.Session found")) { log.error("Missing @WithSession/@Transactional on calling method", e); } throw e; }

Prevention

When it happens

Trigger: Calling any Panache repository/active-record operation from a thread or code path without a Vert.x duplicated context carrying a Hibernate Reactive session marker: background threads, Vert.x worker/blocks, scheduled tasks, plain @ApplicationScoped business methods without @Transactional/@WithSession/@WithTransaction, or code run before the JAX-RS method marker is set.

Common situations: Business methods called from a REST resource but not annotated (inherited annotations from a base class are not honored); using CompletableFuture/executors that lose the context; Quarkus scheduler methods without @WithSession; calling Panache from a Kafka/AMQP consumer without a reactive transaction annotation.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/26aee0897b381123. Report an issue: GitHub.