| name | check-errors |
| description | Find error handling gaps including swallowed exceptions, missing handlers, inconsistent error responses, and reactive error handling issues |
Check Errors Skill
Identify error handling gaps, anti-patterns, and inconsistencies in exception management across the codebase.
Instructions
1. Find Swallowed Exceptions
Search for empty or inadequate catch blocks:
try {
riskyOperation();
} catch (Exception e) {
}
try {
riskyOperation();
} catch (Exception e) {
log.error("Error", e);
}
try {
return fetchData();
} catch (Exception e) {
return null;
}
Use Grep to find:
catch.*\{[\s]*\}
catch.*\{[\s]*/[/*]
catch.*\{[\s]*log\.(error|warn|info)
2. Check Reactive Error Handling
Missing error operators in Mono/Flux chains:
return webClient.get()
.retrieve()
.bodyToMono(Data.class);
return webClient.get()
.retrieve()
.bodyToMono(Data.class)
.onErrorResume(e -> {
log.error("Failed to fetch", e);
return Mono.empty();
});
return service.fetchData()
.onErrorReturn(defaultValue);
return service.fetchData()
.onErrorMap(e -> new DomainException("Fetch failed", e));
Search for chains without error handling:
\.bodyToMono\(.*\);$
\.bodyToFlux\(.*\);$
\.flatMap\(.*\);$
3. Analyze Exception Propagation
Checked vs Unchecked exceptions:
try {
Files.readAllBytes(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
Files.readAllBytes(path);
} catch (IOException e) {
throw new ConfigLoadException("Failed to load config: " + path, e);
}
Search for generic exception wrapping:
throw new RuntimeException\(e\)
throw new RuntimeException\(.*e\)
throw new IllegalStateException\(e\)
4. Controller Error Handling
Check for @ExceptionHandler coverage:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException e) {
return ResponseEntity.status(404).body(new ErrorResponse(e.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneral(Exception e) {
log.error("Unexpected error", e);
return ResponseEntity.status(500).body(new ErrorResponse("Internal error"));
}
}
Verify:
- @ControllerAdvice exists
- Common exceptions are handled (NotFound, BadRequest, etc.)
- Catch-all handler exists
- Error responses are consistent
Check controllers for unhandled exceptions:
@GetMapping("/{id}")
public Mono<Data> getById(@PathVariable int id) {
return service.findById(id);
}
@GetMapping("/{id}")
public Mono<ResponseEntity<Data>> getById(@PathVariable int id) {
return service.findById(id)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
5. Error Response Consistency
Check error response format:
{
"error": "Error message",
"code": "ERROR_CODE",
"timestamp": "2024-01-01T00:00:00Z",
"path": "/api/resource"
}
Find inconsistent error responses:
ResponseEntity.badRequest().body("Error")
ResponseEntity.badRequest().body(Map.of("msg", e))
ResponseEntity.badRequest().body(new Error(e))
6. Null Handling Gaps
Missing null checks:
public void process(Data data) {
String value = data.getValue().toUpperCase();
}
public void process(Data data) {
if (data == null || data.getValue() == null) {
throw new IllegalArgumentException("Data and value required");
}
String value = data.getValue().toUpperCase();
}
public void process(Data data) {
Optional.ofNullable(data)
.map(Data::getValue)
.ifPresent(this::handleValue);
}
Search patterns:
\.get\(\)\.
\.findFirst\(\)\.get
7. Resource Cleanup on Error
Check try-with-resources usage:
InputStream is = new FileInputStream(file);
try {
process(is);
} finally {
is.close();
}
try (InputStream is = new FileInputStream(file)) {
process(is);
}
Check OkHttp response body closure:
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new ApiException("Failed");
}
String body = response.body().string();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new ApiException("Failed: " + response.code());
}
return response.body().string();
}
8. Logging Quality
Check error logging:
log.error("Error occurred");
log.error("Error: " + e.getMessage());
log.info("Error occurred", e);
log.error("Failed to process request for user={}", userId, e);
Search for inadequate logging:
log\.error\("[^"]*"\);$ # error without exception
log\.error\(".*" \+ e\.getMessage # message only, no stack
catch.*\{[^}]*\} # catch without any log
9. Timeout and Retry Handling
Check for timeout handling:
Response response = client.newCall(request).execute();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
mono.timeout(Duration.ofSeconds(30))
.onErrorResume(TimeoutException.class, e -> fallback());
Check for retry logic:
@Retryable(value = ApiException.class, maxAttempts = 3)
public Data fetchData() { ... }
@Recover
public Data fallback(ApiException e) { ... }
mono.retryWhen(Retry.backoff(3, Duration.ofSeconds(1)))
10. Project-Specific Checks
Files to examine:
controller/*.java - HTTP error responses
service/*.java - Business exception handling
service/strategy/*.java - External API error handling
config/*Config.java - Configuration error handling
This project's patterns to verify:
Output Format
## Error Handling Analysis Report
### Summary
| Category | Issues | Severity |
|----------|--------|----------|
| Swallowed Exceptions | X | Critical |
| Missing Reactive Handlers | X | High |
| Inconsistent Error Responses | X | Medium |
| Resource Leaks on Error | X | High |
| Inadequate Logging | X | Medium |
### Critical Issues
#### Swallowed Exception
**File**: `path/to/file.java:line`
**Code**:
```java
try {
externalService.call();
} catch (Exception e) {
// empty
}
Risk: Silent failures, data inconsistency
Fix:
try {
externalService.call();
} catch (Exception e) {
log.error("External service call failed", e);
throw new ServiceException("Failed to call external service", e);
}
High Priority Issues
Missing Reactive Error Handler
File: path/to/file.java:line
Chain: webClient.get()...bodyToMono()
Risk: Unhandled errors propagate to framework
Fix: Add .onErrorResume() or .onErrorReturn()
Resource Leak Risk
File: path/to/file.java:line
Resource: OkHttp Response
Fix: Wrap in try-with-resources
Medium Priority Issues
| File | Line | Issue | Recommendation |
|---|
| Service.java | 42 | Generic RuntimeException wrap | Use domain exception |
| Handler.java | 78 | Log without stack trace | Add exception parameter |
Error Handler Coverage
| Exception Type | Handler Exists | Location |
|---|
| NotFoundException | ✓ | GlobalExceptionHandler:25 |
| ValidationException | ✗ | Missing |
| Generic Exception | ✓ | GlobalExceptionHandler:45 |
Reactive Chains Analysis
| File | Line | Chain | Error Handling |
|---|
| ForecastService | 42 | Mono | ✓ onErrorResume |
| AggregatorService | 78 | Flux | ✗ Missing |
Recommendations
- Critical: Add error handling to empty catch at
File.java:42
- High: Add @ControllerAdvice for ValidationException
- Medium: Standardize error response format across controllers
- Low: Improve error log messages with more context
Error Handling Checklist
## Execution Steps
1. Use `Grep` to find empty/inadequate catch blocks
2. Use `Grep` to find reactive chains without error handling
3. Check for @ControllerAdvice and @ExceptionHandler
4. Analyze error response formats in controllers
5. Find resource usages without try-with-resources
6. Check logging statements in catch blocks
7. Verify timeout and retry configurations
8. Generate comprehensive report
## Notes
- Some "swallowed" exceptions may be intentional (e.g., optional cleanup)
- Reactive error handling is critical - errors should never silently disappear
- This project uses @Retryable in some services - verify @Recover exists
- OkHttp responses MUST be closed, even on error paths
- Empty Mono/Flux is sometimes valid fallback, but should be logged