{"record":{"id":"d5e1ba7f89691932","repo":"apache/shardingsphere","slug":"s-execution-mode-is-required","errorCode":null,"errorMessage":"%s execution_mode is required.","messagePattern":"(.+?) execution_mode is required\\.","errorType":"validation","errorClass":"MCPExecutionModeRequiredException","httpStatus":null,"severity":"error","filePath":"mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java","lineNumber":100,"sourceCode":"        }\n        return SQLExecutionPayload.executed(requestContext.getExecutionFacade().execute(\n                SQLExecutionToolHandlerSupport.createExecutionRequest(requestContext.getSessionIdentity().getSessionId(), toolArguments, sql, CoreToolNames.EXECUTE_UPDATE)));\n    }\n    \n    private ClassificationResult checkUpdateStatement(final MCPFeatureRequestContext requestContext, final MCPToolArguments toolArguments, final String sql) {\n        ClassificationResult classificationResult = SQLExecutionToolHandlerSupport.analyze(requestContext, toolArguments, sql);\n        if (SQLExecutionToolHandlerSupport.isQueryStatement(classificationResult)) {\n            throw new SQLToolMismatchException(\"database_gateway_execute_update does not accept read-only SQL. Use database_gateway_execute_query for read-only SQL.\",\n                    CoreToolNames.EXECUTE_UPDATE, CoreToolNames.EXECUTE_QUERY, classificationResult,\n                    createQuerySuggestedArguments(toolArguments, classificationResult));\n        }\n        return classificationResult;\n    }\n    \n    private String resolveExecutionMode(final MCPToolArguments toolArguments) {\n        String result = toolArguments.getStringArgument(MCPPayloadFieldNames.EXECUTION_MODE);\n        if (result.isEmpty()) {\n            throw new MCPExecutionModeRequiredException(CoreToolNames.EXECUTE_UPDATE, EXECUTION_MODES, createPreviewSuggestedArguments(toolArguments));\n        }\n        if (EXECUTION_MODE_EXECUTE.equals(result) || EXECUTION_MODE_PREVIEW.equals(result)) {\n            return result;\n        }\n        throw new MCPInvalidExecutionModeException(CoreToolNames.EXECUTE_UPDATE, EXECUTION_MODES, createPreviewSuggestedArguments(toolArguments));\n    }\n    \n    private MCPSuccessPayload createPreviewResponse(final MCPToolArguments toolArguments, final ClassificationResult classificationResult) {\n        Map<String, Object> result = new LinkedHashMap<>(17, 1F);\n        result.put(\"response_mode\", MCPResponseMode.PREVIEW);\n        result.put(\"result_kind\", RESULT_KIND_PREVIEW);\n        result.put(MCPPayloadFieldNames.EXECUTION_MODE, EXECUTION_MODE_PREVIEW);\n        result.put(\"preview_semantics\", \"classification_only\");\n        result.put(\"affected_rows_estimated\", false);\n        result.put(\"status\", \"PREVIEWED\");\n        result.put(\"would_execute\", false);\n        result.put(\"statement_class\", classificationResult.getStatementClass().name().toLowerCase(Locale.ENGLISH));\n        result.put(\"statement_type\", classificationResult.getStatementType());","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/apache/shardingsphere/blob/e952770a215630a3659c75d64369168cd3e26b82/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExecuteUpdateToolHandler.java#L82-L118","documentation":"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.","triggerScenarios":"Calling database_gateway_execute_update without the execution_mode argument at all, or with an empty string value.","commonSituations":"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.","solutions":["Add \"execution_mode\": \"execute\" (to apply) or \"execution_mode\": \"preview\" (to classify-only) to the arguments.","Refresh the client/agent prompt with the tool's current input schema.","Default to 'preview' when unsure — it performs classification only and never executes."],"exampleFix":"// before\nawait tools.call('database_gateway_execute_update', { sql: \"DELETE FROM t\" }); // execution_mode is required\n\n// after\nawait tools.call('database_gateway_execute_update', { sql: \"DELETE FROM t\", execution_mode: 'preview' });\n// verified safe -> rerun with execution_mode: 'execute'","handlingStrategy":"validation","validationCode":"// Always set a mode; default to preview when not verified\nfunction updateArgs(sql, { dryRun = true } = {}) {\n  return { sql, execution_mode: dryRun ? 'preview' : 'execute' };\n}\nconst args = updateArgs(sql); // execution_mode present by construction","typeGuard":"function hasExecutionMode(args) {\n  return typeof args.execution_mode === 'string' && args.execution_mode.length > 0;\n}","tryCatchPattern":"try {\n  return await tools.call('database_gateway_execute_update', args);\n} catch (e) {\n  if (/execution_mode is required/.test(e.message)) {\n    return tools.call('database_gateway_execute_update', { ...args, execution_mode: 'preview' });\n  }\n  throw e;\n}","preventionTips":["Make execution_mode a required field in your wrapper around execute_update.","Default to 'preview' and only flip to 'execute' after reviewing the preview.","Refresh tool schemas in agent prompts after server upgrades."],"tags":["mcp","tool-arguments","validation","execution-mode"],"backgroundTag":null,"analyzedSha":"e952770a215630a3659c75d64369168cd3e26b82","analyzedAt":"2026-08-14T13:54:53.392Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}