apache/shardingsphere · error · MCPExecutionModeRequiredException

%s execution_mode is required.

Error message

%s execution_mode is required.

What it means

database_gateway_execute_update requires an explicit execution_mode argument ('execute' or 'preview') because updates are side-effecting; resolveExecutionMode throws MCPExecutionModeRequiredException when the argument is empty. This forces the caller to consciously opt into executing or previewing rather than mutating by default. The exception lists the accepted modes and includes preview-oriented suggested arguments.

Source

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

        }
        return SQLExecutionPayload.executed(requestContext.getExecutionFacade().execute(
                SQLExecutionToolHandlerSupport.createExecutionRequest(requestContext.getSessionIdentity().getSessionId(), toolArguments, sql, CoreToolNames.EXECUTE_UPDATE)));
    }
    
    private ClassificationResult checkUpdateStatement(final MCPFeatureRequestContext requestContext, final MCPToolArguments toolArguments, final String sql) {
        ClassificationResult classificationResult = SQLExecutionToolHandlerSupport.analyze(requestContext, toolArguments, sql);
        if (SQLExecutionToolHandlerSupport.isQueryStatement(classificationResult)) {
            throw new SQLToolMismatchException("database_gateway_execute_update does not accept read-only SQL. Use database_gateway_execute_query for read-only SQL.",
                    CoreToolNames.EXECUTE_UPDATE, CoreToolNames.EXECUTE_QUERY, classificationResult,
                    createQuerySuggestedArguments(toolArguments, classificationResult));
        }
        return classificationResult;
    }
    
    private String resolveExecutionMode(final MCPToolArguments toolArguments) {
        String result = toolArguments.getStringArgument(MCPPayloadFieldNames.EXECUTION_MODE);
        if (result.isEmpty()) {
            throw new MCPExecutionModeRequiredException(CoreToolNames.EXECUTE_UPDATE, EXECUTION_MODES, createPreviewSuggestedArguments(toolArguments));
        }
        if (EXECUTION_MODE_EXECUTE.equals(result) || EXECUTION_MODE_PREVIEW.equals(result)) {
            return result;
        }
        throw new MCPInvalidExecutionModeException(CoreToolNames.EXECUTE_UPDATE, EXECUTION_MODES, createPreviewSuggestedArguments(toolArguments));
    }
    
    private MCPSuccessPayload createPreviewResponse(final MCPToolArguments toolArguments, final ClassificationResult classificationResult) {
        Map<String, Object> result = new LinkedHashMap<>(17, 1F);
        result.put("response_mode", MCPResponseMode.PREVIEW);
        result.put("result_kind", RESULT_KIND_PREVIEW);
        result.put(MCPPayloadFieldNames.EXECUTION_MODE, EXECUTION_MODE_PREVIEW);
        result.put("preview_semantics", "classification_only");
        result.put("affected_rows_estimated", false);
        result.put("status", "PREVIEWED");
        result.put("would_execute", false);
        result.put("statement_class", classificationResult.getStatementClass().name().toLowerCase(Locale.ENGLISH));
        result.put("statement_type", classificationResult.getStatementType());

View on GitHub (pinned to e952770a21)

Solutions

  1. Add "execution_mode": "execute" (to apply) or "execution_mode": "preview" (to classify-only) to the arguments.
  2. Refresh the client/agent prompt with the tool's current input schema.
  3. Default to 'preview' when unsure — it performs classification only and never executes.

Example fix

// before
await tools.call('database_gateway_execute_update', { sql: "DELETE FROM t" }); // execution_mode is required

// after
await tools.call('database_gateway_execute_update', { sql: "DELETE FROM t", execution_mode: 'preview' });
// verified safe -> rerun with execution_mode: 'execute'
Defensive patterns

Strategy: validation

Validate before calling

// Always set a mode; default to preview when not verified
function updateArgs(sql, { dryRun = true } = {}) {
  return { sql, execution_mode: dryRun ? 'preview' : 'execute' };
}
const args = updateArgs(sql); // execution_mode present by construction

Type guard

function hasExecutionMode(args) {
  return typeof args.execution_mode === 'string' && args.execution_mode.length > 0;
}

Try / catch

try {
  return await tools.call('database_gateway_execute_update', args);
} catch (e) {
  if (/execution_mode is required/.test(e.message)) {
    return tools.call('database_gateway_execute_update', { ...args, execution_mode: 'preview' });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling database_gateway_execute_update without the execution_mode argument at all, or with an empty string value.

Common situations: LLM omitting execution_mode from the arguments map; client built before the argument became required (schema change); JSON payload dropping empty-string fields; copy-pasted call examples without the field.

Related errors


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