apache/shenyu · error · IllegalArgumentException
Invalid input JSON format
Error message
Invalid input JSON format
What it means
parseInput parses the tool-call arguments string into a Gson JsonObject. If the parsed result is null (Gson can return null for certain inputs like the literal 'null'), it throws IllegalArgumentException('Invalid input JSON format'). Note the catch block then rethrows a different message ('Invalid JSON format: ...'), so this exact message only appears for the null-parse case (or is wrapped by it if Gson threw).
Solutions
- Make the MCP client send a valid JSON object for arguments; blank input is fine (treated as {}) but 'null' is not.
- Fix client serialization to emit {} when there are no arguments.
- Validate arguments against the tool's input schema before invoking.
Example fix
// before (client)
toolCall(toolName, "null");
// after
toolCall(toolName, "{}"); Defensive patterns
Strategy: validation
Validate before calling
boolean safeArgs(String input) {
if (input == null || input.isBlank() || "null".equalsIgnoreCase(input.trim())) {
return true; // will be treated as empty JsonObject or should be replaced with "{}"
}
try { new com.google.gson.JsonParser().parseString(input); return true; }
catch (Exception e) { return false; }
} Try / catch
try {
return callback.call(args, ctx);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("JSON")) {
return "Invalid arguments: expected a JSON object";
}
throw e;
} Prevention
- Send "{}" for tools with no arguments; never send the literal string null.
- Serialize tool arguments with a JSON library, never string concatenation.
- Validate LLM output against the tool input schema before invoking.
- Blank input is acceptable (treated as empty object) — normalize it client-side.
When it happens
Trigger: An MCP client sends arguments whose parsed JSON yields null — most commonly the JSON string "null", or Gson throwing during fromJson (which lands in the catch and produces error 177's message instead).
Common situations: MCP client sending literal null or empty-semantic arguments; client-side serialization bug emitting 'null' instead of '{}'; mismatch between tool input schema and what the LLM emits.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- Invalid JSON format
- Invalid request body: expected a JSON object
- OpenAPI document is missing the top-level 'servers' field…
- Invalid Swagger JSON format:
- OpenAPI pathKey cannot be null or empty
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/f690945524f2b29b.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/callback/ShenyuToolCallback.java:343
configureShenyuContext(finalExchange, sessionId, requestConfig.getPath(), configStr);
return finalExchange;
}
/**
* Parses the input JSON string into a JsonObject.
*
* @param input the input JSON string
* @return the parsed JsonObject
* @throws IllegalArgumentException if input is not valid JSON
*/
private JsonObject parseInput(final String input) {
try {
if (org.apache.commons.lang3.StringUtils.isBlank(input)) {
return new JsonObject();
}
final JsonObject inputJson = GsonUtils.getInstance().fromJson(input, JsonObject.class);
if (Objects.isNull(inputJson)) {
throw new IllegalArgumentException("Invalid input JSON format");
}
return inputJson;
} catch (Exception e) {
LOG.error("Failed to parse input JSON: {}", e.getMessage());
throw new IllegalArgumentException("Invalid JSON format: " + e.getMessage(), e);
}
}
/**
* Builds request configuration from configuration string and input parameters.
*
* @param configStr the configuration string
* @param inputJson the input parameters
* @return the built request configuration
*/
private RequestConfig buildRequestConfig(final String configStr, final JsonObject inputJson) {
final RequestConfigHelper configHelper = new RequestConfigHelper(configStr);
final JsonObject requestTemplate = configHelper.getRequestTemplate();View on GitHub (pinned to 567142e072)