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
- Start the managed session before the try block so rollback is always valid: startManagedSession(); try { ... commit(); } catch (Exception e) { rollback(); } finally { close(); }.
- Guard rollback with isManagedSessionStarted() in defensive cleanup code.
- 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
- Place startManagedSession() before the try so rollback never runs session-less.
- Never call rollback after close().
- Guard defensive rollback with isManagedSessionStarted().
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
- Error: Cannot commit. No managed session is started.
- Cannot commit, transaction is already closed
- ${mappedStatementId} (batch index #${index}) failed. ${prior
- Could not commit transaction. Cause: {}
- Parameter 'transactionFactory' must not be null
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/4553545cfa604964.
Report an issue: GitHub.