🔴 The Error You're Seeing
Confirm this matches your console output. If it does, you're in the right place.
2026-02-14 09:30:45.200 ERROR 8842 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class com.devinhyderabad.entity.User]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)] with root cause
java.lang.StackOverflowError: null⚡ Quick Fix Works 80% of the time
Add @JsonIgnore to the 'child' side of the relationship to stop Jackson from serializing it.
@ManyToOne
@JoinColumn(name = "department_id")
@JsonIgnore
private Department department;🧠 Why this Happens
Tap to expand the deep technical explanation
Your JPA entities have a bidirectional relationship (e.g., User has a List of Orders, and Order has a reference back to User). When Spring tries to convert the User to JSON, Jackson goes to User -> Orders -> User -> Orders indefinitely until the JVM runs out of stack memory.
The HITEC City Parking Spot Analogy:
Imagine two mirrors facing each other. You look into one mirror and see an infinite tunnel of mirrors reflecting each other. Jackson tries to serialize that infinite tunnel and crashes.
🔁 How to Reproduce Confirm this is your error
Return a JPA entity with a bidirectional @OneToMany/@ManyToOne relationship directly from a controller. Jackson serializes both sides forever and throws JsonMappingException: Infinite recursion (StackOverflowError).
🛠️ Solutions (3 Ways to Fix)
Use @JsonIgnore on the inverse side
👉 Use this for a quick fix when you don't need the related data in the JSON response.
If User has a List of Orders, and Order has a User field, add @JsonIgnore to the User field in the Order class. Jackson will stop traversing there.
@Entity
public class Order {
@ManyToOne
@JsonIgnore // Stops infinite loop
private User user;
}Use @JsonManagedReference and @JsonBackReference
👉 Use this if you want to keep the data in the JSON but break the cycle cleanly.
Annotate the 'parent' side (the List) with @JsonManagedReference, and the 'child' side (the object reference) with @JsonBackReference. Jackson handles the cycle perfectly.
@Entity
public class User {
@OneToMany(mappedBy = "user")
@JsonManagedReference
private List<Order> orders;
}
@Entity
public class Order {
@ManyToOne
@JsonBackReference
private User user;
}Return DTOs instead of Entities
👉 Use this as the enterprise best practice.
Never return JPA Entities directly from @RestController. Map them to DTOs inside your service layer. This completely avoids JSON recursion and lazy loading exceptions.
@GetMapping
public List<UserDTO> getUsers() {
return userService.getAllUsers().stream()
.map(u -> new UserDTO(u.getName(), u.getOrders().size()))
.collect(Collectors.toList());
}📋 Version Notes
Uses Jackson 2.x. Standard recursion handling.
Uses Jackson 2.15+. Stricter memory limits cause StackOverflow to trigger faster.
🛡️ How to Prevent This Next Time
Always separate your database entities from your API responses using Data Transfer Objects (DTOs).