๐Ÿ”ด The Error You're Seeing

Confirm this matches your console output. If it does, you're in the right place.

ERROR LOG2026-02-18 11:20:15.123 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.dao.InvalidDataAccessApiUsageException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.devinhyderabad.entity.User] with root cause org.hibernate.PersistentObjectException: detached entity passed to persist: com.devinhyderabad.entity.User

โšก Quick Fix Works 80% of the time

If using `EntityManager`, change `persist()` to `merge()`. If using Spring Data JPA, ensure your ID isn't manually set before `save()`.

// EntityManager approach entityManager.merge(detachedUser); // Spring Data JPA approach User user = new User(); // user.setId(1L); <-- REMOVE THIS LINE repository.save(user);

๐Ÿง  Why this Happens

Tap to expand the deep technical explanation

You passed an entity to `persist()` (or `save()` on a new entity) that already has its Primary Key (`@Id`) assigned. Hibernate's `persist()` expects a brand new, un-ID'd object. Because the object has an ID, Hibernate assumes it must already exist in the database (it's 'detached'), and refuses to insert it.

The HITEC City Parking Spot Analogy:

Imagine a factory worker trying to stamp a brand-new serial number onto a product, but the product already has a serial number engraved on it. The worker refuses, saying, 'This isn't a new product; it already has an identity.'

๐Ÿ” How to Reproduce Confirm this is your error

Create a new `User` object. Manually set its ID: `user.setId(1L)`. Call `entityManager.persist(user)` or `repository.save(user)` (if the entity's ID generator is set to IDENTITY/SEQUENCE). Run the app.

๐Ÿ› ๏ธ Solutions (5 Ways to Fix)

Solution 1โœ“ Most common cause

Use merge() instead of persist()

๐Ÿ‘‰ Use this if you are using `EntityManager` directly and the object already has an ID.

The `merge()` method tells Hibernate to copy the state of your detached object onto the object in the database (or insert it if it doesn't exist).

// Instead of entityManager.persist(user); entityManager.merge(user);
Solution 2

Remove the manual ID assignment

๐Ÿ‘‰ Use this if you are creating a NEW record but accidentally set the ID yourself.

If your `@Id` is annotated with `@GeneratedValue`, Hibernate will assign the ID. You must not set it manually before saving.

User user = new User(); user.setName("Deva"); // user.setId(1L); <-- REMOVE THIS repository.save(user); // Hibernate generates the ID
Solution 3

Check for cascading relationships

๐Ÿ‘‰ Use this if you are saving a parent object, and the child object has a manually set ID.

If `User` has `@OneToMany(cascade = CascadeType.PERSIST)` to `Order`, and your `Order` object has an ID set, Hibernate will try to persist it and fail. Use `CascadeType.MERGE` instead.

@Entity public class User { @OneToMany(cascade = CascadeType.MERGE) // Change from PERSIST to MERGE private List<Order> orders; }
Solution 4

Fetch the entity before updating

๐Ÿ‘‰ Use this if you are receiving a JSON payload to update an existing record.

Instead of passing the detached JSON object to `save()`, fetch the managed entity from the DB, update its fields, and save it.

@Transactional public void updateUser(Long id, UserRequest req) { User managedUser = repo.findById(id).orElseThrow(); managedUser.setName(req.getName()); repo.save(managedUser); // Safe, it's a managed entity }
Solution 5

Fix @GeneratedValue configuration

๐Ÿ‘‰ Use this if you are using a SEQUENCE or TABLE generator but misconfigured it.

Ensure your `@GeneratedValue` strategy is correct. If it's set to `NONE`, Hibernate expects you to assign the ID, but if you don't, it might treat it as detached.

@Id @GeneratedValue(strategy = GenerationType.IDENTITY) // Ensure strategy is correct private Long id;

๐Ÿ“‹ Version Notes

Spring Boot 2.x

Uses Hibernate 5. Throws PersistentObjectException.

Spring Boot 3.x

Uses Hibernate 6. Identical behavior.

๐Ÿ›ก๏ธ How to Prevent This Next Time

Never manually set the `@Id` field on new entities. Use Spring Data JPA's `save()` method, which internally checks for IDs and routes to `persist()` or `merge()` automatically.

Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase