apache/shenyu · error · HttpClientErrorException
HTTP status error from backend response (dynamic status…
Error message
HTTP status error from backend response (dynamic status from shenyuResponse)
What it means
handlerResponse() maps the gateway's ShenyuResponse to the declared method return type. If the returned status is not 200 it logs the response and throws HttpClientErrorException built from that dynamic status. The message text is generic; the HTTP status code and body on the exception carry the real detail.
Solutions
- Read HttpClientErrorException.getStatusCode() and getResponseBodyAsString() to identify the exact upstream failure.
- Check that the annotation path/verb matches the route configured in the ShenYu admin for this service.
- If the backend is failing, fix or restart it; check gateway logs for the forwarded request.
- Declare the return type as ShenyuResponse when you want to inspect non-200 statuses yourself instead of throwing.
Example fix
// before
@Get("/order/detail")
OrderDTO getById(Long id); // throws on 404
// after (inspect status manually)
@Get("/order/detail")
ShenyuResponse getById(Long id);
if (response.getStatus() == 404) { /* handle */ } Defensive patterns
Strategy: try-catch
Try / catch
try {
return orderApi.getById(id);
} catch (HttpClientErrorException e) {
switch (e.getStatusCode().value()) {
case 404: return null;
case 401: case 403: throw new AuthException(e);
default: throw new BackendException(e.getResponseBodyAsString(), e);
}
} Prevention
- Keep annotation paths/verbs in sync with ShenYu admin route configuration.
- Catch HttpClientErrorException and branch on status instead of letting it bubble.
- Use ShenyuResponse return type when you need to inspect non-200 responses.
- Verify backend health before blaming the gateway; check gateway logs for forwarded errors.
When it happens
Trigger: The gateway/backend returned a non-200 status on a @ShenyuClient call whose return type is not ShenyuResponse/void — 404 for a wrong path, 500 from the backend, 401/403 from auth filters.
Common situations: Path or HTTP verb mismatch between interface annotation and gateway route; backend service down behind the gateway; authentication plugin rejecting the request; payload failing backend validation.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- accessToken is null
- Failed to get Swagger document, HTTP status code:
- group param invalid
- Invalid URI construction
- Max response body size must not be negative
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/c6776b8f5dd863ee.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/proxy/ShenyuClientMethodHandler.java:84
*
* @param args args
* @return {@link Object}
* @throws IOException err
*/
public Object invoke(final Object[] args) throws IOException {
final ShenyuRequest shenyuRequest = targetProcessor(requestTemplate, args);
final ShenyuResponse shenyuResponse = shenyuHttpClient.execute(shenyuRequest);
return handlerResponse(shenyuResponse, shenyuRequest.getRequestTemplate().getReturnType());
}
private Object handlerResponse(final ShenyuResponse shenyuResponse, final Class<?> returnType) {
if (Objects.isNull(shenyuResponse) || void.class == returnType) {
return null;
} else if (ShenyuResponse.class == returnType) {
return shenyuResponse;
} else if (shenyuResponse.getStatus() != HttpStatus.OK.value()) {
log.warn("handlerResponse http status warn shenyuResponse {}", JsonUtils.toJson(shenyuResponse));
throw new HttpClientErrorException(HttpStatus.valueOf(shenyuResponse.getStatus()));
} else if (StringUtils.hasText(shenyuResponse.getBody())) {
return JsonUtils.jsonToObject(shenyuResponse.getBody(), returnType);
} else {
return null;
}
}
private ShenyuRequest targetProcessor(final RequestTemplate requestTemplate, final Object[] args) {
final RequestTemplate requestTemplateFrom = RequestTemplate.from(requestTemplate);
ShenyuRequest request = requestTemplateFrom.request();
for (RequestTemplate.ParamMetadata paramMetadata : requestTemplateFrom.getParamMetadataList()) {
final Annotation[] paramAnnotations = paramMetadata.getParamAnnotations();
for (Annotation paramAnnotation : paramAnnotations) {
final AnnotatedParameterProcessor processor = annotatedArgumentProcessors.get(paramAnnotation.annotationType());
if (ObjectUtils.isEmpty(processor)) {
continue;
}
processor.processArgument(request, paramAnnotation, args[paramMetadata.getParamIndexOnMethod()]);View on GitHub (pinned to 567142e072)