In Spring Boot applications, a 404 Not Found error typically means the requested URL doesnโt match any controller endpoint, or you're deliberately signaling that a resource wasn't found. This article covers:
- Common causes of 404s in Spring Boot
- How to debug unexpected 404 errors
- Multiple ways to explicitly return 404 responses in REST APIs
- How to use custom exceptions and global exception handling
Use these strategies to build reliable, user-friendly RESTful services.
โ Common Reasons Spring Boot Returns a 404
๐น 1. Incorrect URL or Path
Ensure that the URL you're accessing matches your controller's path and method.
java
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
// URL must be: http://localhost:8080/api/hello
๐น 2. Controller Not Scanned
Controllers must be in packages scanned by Spring Boot.
java
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
// OR explicitly define scanning:
@SpringBootApplication
@ComponentScan(basePackages = "com.example.controllers")
๐น 3. Wrong HTTP Method
Check that your controller method matches the request method (e.g., GET vs POST).
java
// If using POST, make sure your client sends POST
@PostMapping("/submit")
public String submitData() {
return "Submitted!";
}
๐น 4. Missing View in Thymeleaf Apps
If using Thymeleaf, ensure templates exist in src/main/resources/templates
.
๐น 5. Custom Error Handling Conflicts
Check for misconfigured @ControllerAdvice
that may intercept or redirect requests.
โ
How to Explicitly Return a 404 Response
โ
1. Using ResponseStatusException
A quick and direct way to throw a 404:
java
@GetMapping("/item/{id}")
public String getItem(@PathVariable String id) {
boolean exists = false;
if (!exists) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Item not found");
}
return "Item details";
}
โ
2. Returning ResponseEntity
java
@GetMapping("/item/{id}")
public ResponseEntity<String> getItem(@PathVariable String id) {
boolean exists = false;
if (!exists) {
return new ResponseEntity<>("Item not found", HttpStatus.NOT_FOUND);
}
return new ResponseEntity<>("Item details", HttpStatus.OK);
}
โ
3. Custom Exception with @ResponseStatus
java
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ItemNotFoundException extends RuntimeException {
public ItemNotFoundException(String message) {
super(message);
}
}
// Controller
@GetMapping("/item/{id}")
public String getItem(@PathVariable String id) {
throw new ItemNotFoundException("Item not found");
}
โ
4. Global Exception Handling with @ControllerAdvice
Create a centralized handler for cleaner code:
java
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ItemNotFoundException.class)
public ResponseEntity<String> handleItemNotFound(ItemNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
๐งช Bonus Tips for Troubleshooting
- โ
Enable Debug Logging to view endpoint mappings:
yaml
logging:
level:
org.springframework.web: DEBUG
- โ
Check Request URL and Method in Postman or browser
- โ
Test with curl to confirm endpoint response
๐ Summary Table
StrategyPurposeResponseStatusException
Quick way to return 404ResponseEntity
with 404 statusFine-grained response controlCustom Exception with @ResponseStatus
Clean semantic exception mapping@ControllerAdvice
global handlerCentralized error handling