apache/shenyu · error · ShenyuException
response modify failure.
Error message
response modify failure. %s
What it means
ModifyResponsePlugin.writeWith reads the upstream response body and modifyBody rewrites the JSON using JsonPath operations (add/replace/remove body keys per the rule handle). Any exception during parsing or modification (invalid JSON, bad JsonPath expressions, missing keys) is wrapped in a ShenyuException with the message 'response modify failure.' plus the original message.
Solutions
- Inspect the LOG.error('modify response error', e) stack trace to find the underlying cause (JsonPath parse error vs. path evaluation).
- Verify the upstream actually returns JSON for requests matching this modify-response rule; add a condition so non-JSON responses bypass the rule.
- Check the rule handle config: confirm every JsonPath key (add/replace/remove) exists in the response body or use safe path operations.
- Test the rule with a representative response body using a JsonPath evaluator before deploying.
Defensive patterns
Strategy: try-catch
Validate before calling
// validate upstream body is JSON before enabling the rule
try {
JsonPath.parse(body);
} catch (Exception e) {
// bypass modify-response rule for non-JSON bodies
} Try / catch
try {
return chain.writeWith(exchange);
} catch (ShenyuException e) {
LOG.error("response modify failed: {}", e.getLocalizedMessage());
return setErrorResponse(exchange, 500);
} Prevention
- Scope modify-response rules with match conditions so only JSON responses are processed.
- Validate JsonPath expressions against real response samples before publishing rules.
- Use optional/safe JsonPath operations for keys that may be absent.
- Watch the 'modify response error' logs to catch rule/body mismatches early.
When it happens
Trigger: A response passes through ModifyResponsePlugin with a rule handle containing addBodyKeys/replaceBodyKeys/removeBodyKeys, and the upstream body is not valid JSON, or a JsonPath expression in the rule handle does not match/apply to the body structure.
Common situations: Upstream returns HTML/plain text or an error page instead of JSON while a modify-response rule expects JSON; operator configures a JsonPath key that doesn't exist in the response; upstream response is empty or truncated; charset mismatches corrupt the body string.
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 Swagger JSON format:
- The date should be a string value
- Invalid request body: expected a JSON object
- Failed to parse request body into ChatCompletionRequest
- Invalid input JSON format
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/8a1d6487cbdb340d.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-plugin/shenyu-plugin-modify-response/src/main/java/org/apache/shenyu/plugin/modify/response/ModifyResponsePlugin.java:162
// reset http status
if (this.ruleHandle.getStatusCode() > 0) {
this.setStatusCode(HttpStatus.valueOf(this.ruleHandle.getStatusCode()));
}
// reset http headers
this.getDelegate().getHeaders().clear();
this.getDelegate().getHeaders().putAll(httpHeaders);
}
private byte[] modifyBody(final byte[] responseBody) {
try {
String bodyStr = modifyBody(new String(responseBody, StandardCharsets.UTF_8));
LOG.info("the body string {}", bodyStr);
return bodyStr.getBytes(StandardCharsets.UTF_8);
} catch (Exception e) {
LOG.error("modify response error", e);
throw new ShenyuException(String.format("response modify failure. %s", e.getLocalizedMessage()));
}
}
private String modifyBody(final String jsonValue) {
DocumentContext context = JsonPath.parse(jsonValue);
if (CollectionUtils.isNotEmpty(this.ruleHandle.getAddBodyKeys())) {
this.ruleHandle.getAddBodyKeys().forEach(info -> context.put(info.getPath(), info.getKey(), info.getValue()));
}
if (CollectionUtils.isNotEmpty(this.ruleHandle.getReplaceBodyKeys())) {
this.ruleHandle.getReplaceBodyKeys().forEach(info -> context.renameKey(info.getPath(), info.getKey(), info.getValue()));
}
if (CollectionUtils.isNotEmpty(this.ruleHandle.getRemoveBodyKeys())) {
this.ruleHandle.getRemoveBodyKeys().forEach(context::delete);
}
return context.jsonString();
}
}
}View on GitHub (pinned to 567142e072)