apache/shardingsphere · error · MCPInvalidRequestException

Statement is not a transaction command.

Error message

Statement is not a transaction command.

What it means

Thrown by MCPJdbcTransactionStatementExecutor.executeSavepointStatement when the transaction-statement router cannot classify the statement as SAVEPOINT, ROLLBACK TO SAVEPOINT, or RELEASE SAVEPOINT. It is an MCPInvalidRequestException: the caller asked the transaction endpoint to run something that is not one of the three recognized savepoint commands.

Source

Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPJdbcTransactionStatementExecutor.java:84

                    0, 0, classificationResult.getNormalizedSql());
        } catch (final IllegalArgumentException ex) {
            throw new MCPInvalidRequestException(ex.getMessage(), ex);
        } catch (final IllegalStateException ex) {
            throw new MCPTransactionStateException(ex.getMessage(), ex);
        }
    }
    
    private void executeSavepointStatement(final String sessionId, final MCPDatabaseCapability databaseCapability, final ClassificationResult classificationResult) {
        String statementType = classificationResult.getStatementType();
        String savepointName = classificationResult.getSavepointName().orElse("");
        if ("SAVEPOINT".equals(statementType)) {
            executeSavepoint(sessionId, databaseCapability, getRequiredSavepointName(savepointName));
        } else if ("ROLLBACK TO SAVEPOINT".equals(statementType)) {
            executeRollbackSavepoint(sessionId, databaseCapability, getRequiredSavepointName(savepointName));
        } else if ("RELEASE SAVEPOINT".equals(statementType)) {
            executeReleaseSavepoint(sessionId, databaseCapability, getRequiredSavepointName(savepointName));
        } else {
            throw new MCPInvalidRequestException("Statement is not a transaction command.");
        }
    }
    
    private String getRequiredSavepointName(final String savepointName) {
        String result = savepointName.trim();
        ShardingSpherePreconditions.checkNotEmpty(result, () -> new IllegalArgumentException("Savepoint name is required."));
        return result;
    }
    
    private void executeBeginTransaction(final String sessionId, final String databaseName, final MCPDatabaseCapability databaseCapability) {
        ShardingSpherePreconditions.checkState(databaseCapability.supportsTransactionControl(), () -> new MCPUnsupportedException("Transaction control is not supported."));
        sessionManager.getTransactionResourceManager().beginTransaction(sessionId, databaseName);
    }
    
    private void executeCommit(final String sessionId, final MCPDatabaseCapability databaseCapability) {
        ShardingSpherePreconditions.checkState(databaseCapability.supportsTransactionControl(), () -> new MCPUnsupportedException("Transaction control is not supported."));
        sessionManager.getTransactionResourceManager().commitTransaction(sessionId);
    }

View on GitHub (pinned to e952770a21)

Solutions

  1. Use the full canonical forms: `SAVEPOINT name`, `ROLLBACK TO SAVEPOINT name`, `RELEASE SAVEPOINT name`
  2. Verify you are calling the transaction tool with classified transaction statements, not raw arbitrary SQL
  3. If the failure persists with canonical SQL, check that the classifier produced the expected statementType and report the mismatch against MCPJdbcTransactionStatementExecutor

Example fix

-- before
ROLLBACK TO sp1;
RELEASE sp1;

-- after
ROLLBACK TO SAVEPOINT sp1;
RELEASE SAVEPOINT sp1;
Defensive patterns

Strategy: validation

Validate before calling

// Only submit canonical savepoint forms to the transaction tool
private static final Set<String> CANONICAL = Set.of("SAVEPOINT", "ROLLBACK TO SAVEPOINT", "RELEASE SAVEPOINT");
if (!CANONICAL.contains(classify(sql))) throw new IllegalArgumentException("Not a supported transaction command: " + sql);

Try / catch

try {
    transactionTool.execute(sessionId, sql);
} catch (MCPInvalidRequestException e) {
    if (e.getMessage().contains("not a transaction command")) {
        // send through the normal execute tool instead if it is plain SQL
    }
}

Prevention

When it happens

Trigger: executeSavepointStatement() is entered with a classificationResult whose statementType is none of "SAVEPOINT", "ROLLBACK TO SAVEPOINT", "RELEASE SAVEPOINT" — typically a classifier mismatch, e.g. `RELEASE sp1` without the SAVEPOINT keyword, `ROLLBACK TO sp1`, or a custom statement type string passed directly to the transaction tool.

Common situations: Dialect differences: PostgreSQL allows `RELEASE SAVEPOINT sp` and MySQL uses `RELEASE SAVEPOINT` only, so scripts written for one engine send short forms the classifier does not produce; calling the transaction MCP tool with free-text SQL instead of going through SQL classification; version changes that rename statement types.

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/009407087d2ab8f6. Report an issue: GitHub.