mybatis/mybatis-3 · error · SqlSessionException

Error: Cannot rollback. No managed session is started.

Error message

Error:  Cannot rollback.  No managed session is started.

What it means

SqlSessionManager.rollback() throws SqlSessionException 'Cannot rollback. No managed session is started.' when the thread-local managed session is null. Rollback targets the transaction bound to the managed session; with no session started there is nothing to roll back and the manager treats it as a programming error rather than a no-op.

Source

Thrown at src/main/java/org/apache/ibatis/session/SqlSessionManager.java:302

      throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
    }
    sqlSession.commit();
  }

  @Override
  public void commit(boolean force) {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
    }
    sqlSession.commit(force);
  }

  @Override
  public void rollback() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
    }
    sqlSession.rollback();
  }

  @Override
  public void rollback(boolean force) {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
    }
    sqlSession.rollback(force);
  }

  @Override
  public List<BatchResult> flushStatements() {
    final SqlSession sqlSession = localSqlSession.get();
    if (sqlSession == null) {
      throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");

View on GitHub (pinned to 008069adb1)

Solutions

  1. Start the managed session before the try block so rollback is always valid: startManagedSession(); try { ... commit(); } catch (Exception e) { rollback(); } finally { close(); }.
  2. Guard rollback with isManagedSessionStarted() in defensive cleanup code.
  3. Do not call rollback after close(); close() ends the lifecycle.

Example fix

// before
try { sqlSessionManager.update(...); sqlSessionManager.commit(); }
catch (Exception e) { sqlSessionManager.rollback(); } // may throw if start failed
// after
sqlSessionManager.startManagedSession();
try { sqlSessionManager.update(...); sqlSessionManager.commit(); }
catch (Exception e) { sqlSessionManager.rollback(); }
finally { sqlSessionManager.close(); }
Defensive patterns

Strategy: validation

Validate before calling

sqlSessionManager.startManagedSession();
try { /* work */ sqlSessionManager.commit(); }
catch (Exception e) { sqlSessionManager.rollback(); throw e; }
finally { sqlSessionManager.close(); }

Prevention

When it happens

Trigger: rollback() in a catch block when startManagedSession() itself failed or was skipped; rollback after close(); rollback on a thread that never started the session.

Common situations: Exception paths where the session-start line is inside the try and never executed; cleanup code in finally blocks that assumes a session exists; multi-threaded request handling.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/4553545cfa604964. Report an issue: GitHub.