Success Response Status Returned From Catch Block
ID |
java.spring_response_status_mismatch |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
best-practice, reliability, spring |
Description
Reports a returned ResponseEntity.status(HttpStatus.X) carrying a success or redirect code (1xx/2xx/3xx) from inside a catch block.
Rationale
The HTTP status code is the client’s only signal of whether an operation succeeded. Returning a success or redirect code from a catch block — after an exception has already been thrown — tells every caller the request succeeded when it did not. The response is actively misleading, and nothing else in the request/response cycle catches the mistake.
The mirror image — an error code returned from the try block — is deliberately not reported. A try body is simply where a handler does its work, and returning 404, 409 or 500 from it after an ordinary validation or lookup failure is the normal way to write a controller, not a contradiction.
The call is attributed to the nearest enclosing catch: a finally block, a lambda body, an enclosing try reached first, and a call with no enclosing catch at all are all a different control-flow context and are not reported. The status code is read only when it is a plain HttpStatus.CONSTANT reference recognized as an HTTP status name; a variable, a computed value, or an unrecognized constant name is not resolved.
// Bad - the lookup threw, yet the client is told the request succeeded
public ResponseEntity<User> getUser(Long id) {
try {
User user = userService.getUserById(id);
return ResponseEntity.status(HttpStatus.OK).body(user);
} catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.OK).build();
}
}
Remediation
Return an error code from the catch block, matching what actually happened.
// Good - status matches what actually happened
public ResponseEntity<User> getUser(Long id) {
try {
User user = userService.getUserById(id);
return ResponseEntity.status(HttpStatus.OK).body(user);
} catch (UserNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}