apache/shardingsphere · error · MCPInvalidExecutionModeException
%s execution_mode must be one of %s.
Error message
%s execution_mode must be one of %s.
What it means
After confirming execution_mode is present, resolveExecutionMode accepts only the exact values 'execute' or 'preview'; anything else throws MCPInvalidExecutionModeException ('%s execution_mode must be one of %s.'). The strict whitelist prevents accidental mutations via fuzzy values like 'run', 'dry-run', or differently-cased strings. Suggested arguments for a preview retry are attached to the exception.
Source
Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java:105
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());
result.put("normalized_sql", classificationResult.getNormalizedSql());
result.put("side_effect_scope", createSideEffectScope(classificationResult));
classificationResult.getTargetObjectName().ifPresent(optional -> result.put("target_object", optional));
classificationResult.getSavepointName().ifPresent(optional -> result.put("savepoint", optional));
result.put("review_guidance", createReviewGuidance(classificationResult));View on GitHub (pinned to e952770a21)
Solutions
- Use exactly 'execute' or 'preview' (lowercase, no whitespace).
- Map client-side enums: dryRun->'preview', everything-else->'execute' explicitly.
- Trim and lowercase execution_mode before sending.
Example fix
// before
await tools.call('database_gateway_execute_update', { sql, execution_mode: 'dry-run' }); // must be one of [execute, preview]
// after
const mode = opts.dryRun ? 'preview' : 'execute';
await tools.call('database_gateway_execute_update', { sql, execution_mode: mode }); Defensive patterns
Strategy: validation
Validate before calling
const EXECUTION_MODES = new Set(['execute', 'preview']);
function normalizeMode(raw) {
const mode = String(raw ?? '').trim().toLowerCase();
if (!EXECUTION_MODES.has(mode)) throw new Error(`execution_mode must be one of [execute, preview], got '${raw}'`);
return mode;
}
const args = { sql, execution_mode: normalizeMode(userChoice) }; Type guard
function isExecutionMode(value) {
return value === 'execute' || value === 'preview';
} Try / catch
try {
return await tools.call('database_gateway_execute_update', args);
} catch (e) {
if (/execution_mode must be one of/.test(e.message)) {
return tools.call('database_gateway_execute_update', { ...args, execution_mode: args.dryRun ? 'preview' : 'execute' });
}
throw e;
} Prevention
- Whitelist and normalize execution_mode to exact lowercase 'execute'/'preview'.
- Map your client's enum (dryRun etc.) to the two contract values before sending.
- Trim whitespace; the comparison is exact.
When it happens
Trigger: Passing execution_mode values such as 'EXECUTE' (wrong case), 'run', 'dry_run', 'dry-run', 'apply', or trailing whitespace — anything not exactly 'execute' or 'preview'.
Common situations: LLM paraphrasing the mode; enum mapping from a client that uses different names ('dry-run' for preview); case-sensitivity surprises; whitespace from templated payloads.
Related errors
- %s execution_mode is required.
- Completion argument `%s` is not declared for %s `%s`.
- %s must be an integer between %d and %d.
- %s execution_mode is required.
- %s execution_mode must be one of %s.
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/2905c1c4566e40eb.
Report an issue: GitHub.