ORA-08177

ORA-08177: Why You're Seeing It and the Fix That Works

ORA-08177 pops up when two transactions try to edit the same rows at once. You'll need to retry or change isolation. Here's the breakdown.

Quick answer: Retry the entire transaction after catching ORA-08177, or switch to READ COMMITTED isolation if you don't need strict consistency.

ORA-08177 shows up when you're running in SERIALIZABLE isolation mode and two transactions try to modify the same data at the same time. Oracle uses a snapshot of the database at the start of your transaction. When you try to update a row that another transaction has already changed and committed after your snapshot was taken, Oracle throws ORA-08177. It's not a data corruption issue—it's a conflict detection mechanism. The database is telling you, "Your view of the data is stale, so I won't let you overwrite someone else's work."

You'll often see this in apps that process financial transactions, like a banking system where two tellers update the same account balance, or in batch jobs that update overlapping ranges of rows. A common trigger: you run a report that updates a summary table while another session does the same thing.

Fix It in 5 Steps

  1. Identify which transactions are conflicting. Run this query to see active sessions and their SQL:
SELECT s.sid, s.serial#, s.status, q.sql_text
FROM v$session s, v$sql q
WHERE s.sql_id = q.sql_id
AND s.status = 'ACTIVE';

You'll see a list. Look for two sessions updating the same table. That's your culprit.

  1. Check your isolation level. In your application code, look for SET TRANSACTION ISOLATION LEVEL SERIALIZABLE or a JDBC connection property like setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE). If you find it, that's why you're here.
  2. Catch the error and retry. Wrap your transaction logic in a loop that catches ORA-08177 and re-runs the whole thing. Here's a PL/SQL example:
DECLARE
  attempts NUMBER := 0;
BEGIN
  LOOP
    BEGIN
      -- Your transaction here
      UPDATE accounts SET balance = balance - 100 WHERE id = 42;
      COMMIT;
      EXIT; -- success
    EXCEPTION
      WHEN OTHERS THEN
        IF SQLCODE = -8177 AND attempts < 5 THEN
          attempts := attempts + 1;
          ROLLBACK;
        ELSE
          RAISE;
        END IF;
    END;
  END LOOP;
END;

After you catch and rollback, the next attempt gets a fresh snapshot, so it won't conflict again—unless another session keeps stepping on you.

  1. If retries don't work, check for long-running transactions. Look at v$transaction to see how long other sessions have been open:
SELECT t.sid, t.used_ublk, t.start_time
FROM v$transaction t;

If you see a session that's been running for hours, it's holding locks and causing your conflicts. You might need to contact that user and ask them to commit or rollback. In a development environment, you can kill the session with ALTER SYSTEM KILL SESSION 'sid,serial#'.

  1. If you can't change the app code, switch isolation at the session level. Run this before your transaction:
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

But do this only if your business logic doesn't depend on seeing a consistent snapshot across multiple queries. You'll get fewer conflicts, but you might see data that changes mid-transaction.

Alternative Fixes If the Main One Fails

Sometimes retrying isn't enough because the conflict is frequent. Try these:

  • Serialize the transactions at the application level. Use a lock table or a DBMS_LOCK to ensure only one process does the update sequence at a time. For example, call DBMS_LOCK.REQUEST(12345, timeout => 60) before the transaction and release it after.
  • Use SELECT FOR UPDATE to lock rows before updating. This forces other transactions to wait, but it can cause deadlocks if you're not careful. Lock rows in a consistent order.
  • Separate the conflicting operations. If two jobs update the same table, stagger their schedules or partition the data so each job touches different rows.

The real fix depends on your workload. For most apps, retrying is the standard pattern. But if you're seeing this error constantly, you've got a design issue—too many writers on the same data.

Prevention Tips

You can avoid ORA-08177 before it happens:

  • Use READ COMMITTED for most transactions. Oracle's default is the right choice for 95% of use cases. Serializable is only for specific reporting or analytics where you need a point-in-time view.
  • Keep transactions short. The longer a serializable transaction runs, the higher the chance someone else modifies the same data. Commit as soon as possible.
  • Design your app to handle retries gracefully. Even with READ COMMITTED, you might get deadlocks (ORA-00060), so a retry loop is good practice anyway.
  • If you must use serializable, ensure your queries are index-driven and touch the smallest set of rows possible. Full table scans increase the chance of conflicts because Oracle locks more rows in the snapshot.

I've seen teams waste days trying to tune around this error. The pragmatic answer is almost always: retry and move on. If that doesn't work, you're probably using the wrong isolation level for the job.

Related Errors in Database Errors
Table row count wrong after MySQL restore? Fix it here 2002 (HY000) MySQL 2002 Socket Error: Quick Fix That Works on Ubuntu & Debian MySQL Event Scheduler Won't Run Events on Server Restart 0XC022000E STATUS_FWP_TXN_IN_PROGRESS (0XC022000E) Fix – No Call Inside Transaction

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.