apache/shardingsphere · error · MCPInvalidApprovedStepsException
approved_steps must contain only %s.
Error message
approved_steps must contain only %s.
What it means
Thrown by WorkflowExecutionService.requireApprovedSteps when the approved_steps list on an apply request contains at least one value outside ALLOWED_APPROVAL_STEPS. Null, absent, or empty lists are allowed (no approval filtering); only an unrecognized step name triggers MCPInvalidApprovedStepsException, which carries the allowed set and preview-suggested arguments.
Source
Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/workflow/WorkflowExecutionService.java:122
private String requireExecutionMode(final WorkflowContextSnapshot snapshot, final String executionMode) {
if (executionMode.isEmpty()) {
throw new MCPExecutionModeRequiredException(WorkflowToolDescriptors.APPLY_TOOL_NAME, EXECUTION_MODES, createPreviewSuggestedArguments(snapshot));
}
String result = executionMode.toLowerCase(Locale.ENGLISH);
if (!EXECUTION_MODES.contains(result)) {
throw new MCPInvalidExecutionModeException(WorkflowToolDescriptors.APPLY_TOOL_NAME, EXECUTION_MODES, createPreviewSuggestedArguments(snapshot));
}
return result;
}
private void requireApprovedSteps(final WorkflowContextSnapshot snapshot, final List<String> approvedSteps) {
if (null == approvedSteps || approvedSteps.isEmpty()) {
return;
}
for (String each : approvedSteps) {
if (!ALLOWED_APPROVAL_STEPS.contains(each)) {
throw new MCPInvalidApprovedStepsException(ALLOWED_APPROVAL_STEPS, createPreviewSuggestedArguments(snapshot));
}
}
}
private Map<String, Object> checkApplyPreconditions(final String sessionId, final WorkflowContextSnapshot snapshot, final String executionMode,
final List<String> approvedSteps) {
if (!WorkflowLifecycleUtils.isOwnedBySession(sessionId, snapshot)) {
return createRejectedResponse(snapshot, executionMode, WorkflowIssueCode.SESSION_OWNERSHIP_MISMATCH, "The workflow plan belongs to another MCP session.",
"Continue the workflow from the same session that created the plan.");
}
if (!isApplicableStatus(snapshot)) {
return createRejectedResponse(snapshot, executionMode, WorkflowIssueCode.WORKFLOW_STATUS_INVALID,
String.format("Workflow status `%s` cannot enter apply in the current lifecycle.", snapshot.getStatus()),
"Plan the workflow again or continue from a reviewable status.");
}
if (WorkflowLifecycle.EXECUTION_MODE_REVIEW_THEN_EXECUTE.equals(executionMode) && !WorkflowLifecycle.STATUS_PREVIEWED.equalsIgnoreCase(snapshot.getStatus())) {
return createRejectedResponse(snapshot, executionMode, WorkflowIssueCode.WORKFLOW_STATUS_INVALID,
"Automatic workflow execution requires an execution_mode=preview call first.",View on GitHub (pinned to e952770a21)
Solutions
- Use only the step identifiers listed in the MCPInvalidApprovedStepsException payload, matching exactly (no case or wording improvisation).
- If you do not need step-level approval, omit approved_steps or send an empty list rather than guessing names.
- Echo the step identifiers verbatim from the workflow plan artifact the plan tool returned, not from prose summaries.
Example fix
// before
arguments.put("approved_steps", List.of("apply-everything"));
// after
arguments.put("approved_steps", List.of(/* exact identifiers from the plan artifact */)); Defensive patterns
Strategy: validation
Validate before calling
List<String> unknown = approvedSteps.stream().filter(s -> !ALLOWED_APPROVAL_STEPS.contains(s)).toList();
if (!unknown.isEmpty()) { throw new IllegalArgumentException("unknown steps: " + unknown); } Type guard
const stepsOk = steps => steps == null || steps.every(s => ALLOWED_APPROVAL_STEPS.includes(s));
Try / catch
try {
applyTool.call(request);
} catch (final MCPInvalidApprovedStepsException ex) {
// drop invented step names; use only identifiers from the plan artifact or omit approved_steps
} Prevention
- Echo machine step identifiers from the plan tool output, never prose
- Omit approved_steps entirely when step filtering is not needed
- Re-derive the allowed set after workflow engine upgrades
When it happens
Trigger: Sending approved_steps such as ["everything"] or ["APPLY"] when only specific step identifiers (the values in ALLOWED_APPROVAL_STEPS) are accepted. Any single bad entry rejects the whole list.
Common situations: An agent inventing step names to force full auto-apply, mismatched step vocabulary after a workflow engine upgrade, or free-text step labels copied from the plan's human-readable output instead of the machine identifiers.
Related errors
- %s execution_mode is required.
- %s execution_mode must be one of %s.
- Completion argument `%s` is not declared for %s `%s`.
- database_gateway_execute_query only supports parser-approved
- database_gateway_execute_update does not accept read-only SQ
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/722ba7d658beacad.
Report an issue: GitHub.