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

  1. Inspect the LOG.error('modify response error', e) stack trace to find the underlying cause (JsonPath parse error vs. path evaluation).
  2. Verify the upstream actually returns JSON for requests matching this modify-response rule; add a condition so non-JSON responses bypass the rule.
  3. Check the rule handle config: confirm every JsonPath key (add/replace/remove) exists in the response body or use safe path operations.
  4. 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

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


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)