Home › Database › ORA-04068: Midday Hotfix Broke 30% of Checkouts
Intermediate 3 min · October 27, 2026
ORA-04068 and ORA-04063: Existing State of Packages Discarded / Package Has Errors

ORA-04068: Midday Hotfix Broke 30% of Checkouts

ORA-04068 means a package your session already used was recompiled, so its state was thrown away.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
✓ Production
production tested
October 27, 2026
last updated
2,087
articles · all by Naren
Before you start⏱ 20 min
  • ✓Basic PL/SQL syntax (packages, procedures, functions)
  • ✓Familiarity with Oracle SQL*Plus or SQL Developer
  • ✓Understanding of database sessions and transactions
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
⚡Quick Answer
  • ORA-04068: a package your session already used was recompiled, so Oracle discarded that session's package state. The next call reinitialises it and succeeds, so a single retry works.
  • It does not roll back your transaction. Only the failing call errors; uncommitted work stays pending until your code commits or rolls back.
  • Prevent it by deploying stateful packages in a maintenance window, recycling connection pools after deploys, moving state out of packages, or using Edition-Based Redefinition.
  • ORA-04063: the object is INVALID. Run SHOW ERRORS (or query USER_ERRORS), fix the real error, which is often in a dependency, and recompile.
✦ Definition~90s read
What is ORA-04068 and ORA-04063?

ORA-04068 (existing state of packages has been discarded) is raised the first time a session calls a package after that package was recompiled, if the package holds session state: package-level variables, constants or cursors. The package itself is fine; the session's copy of its state is gone.

★
Imagine a cashier who keeps a running tally in their head.

ORA-04063 (package body has errors) is different: the package is INVALID and cannot run at all until it compiles cleanly.

Plain-English First

Imagine a cashier who keeps a running tally in their head. Mid-shift, management swaps the till software. The cashier's tally no longer matches the new system, so they shout "lost my count!" once, start a fresh tally and carry on. That shout is ORA-04068. ORA-04063 is when the new till software won't even boot: nobody can use it until it's fixed.

ORA-04068 looks like a random glitch: some sessions fail, others don't, and a retry works. It isn't random. It fires exactly once in every session that had already used a package before someone recompiled it. ORA-04063 is its louder sibling: the package didn't compile, so every caller fails until it does. This guide explains what package state is, why a deploy discards it, how to tell the two errors apart from the error stack, and the deployment patterns that keep both out of your incident channel.

Why Oracle Discards Package State (And Why It's Not a Bug)

A PL/SQL package can hold session state: variables, constants and cursors declared at package level, in the spec or the body. Each session gets its own private copy the first time it touches the package, and that copy lives until the session ends. When the package is recompiled, Oracle can't map the old state onto the new code, so it throws the state away. The next call from any session that already held state raises ORA-04068, and the stack usually adds ORA-04061, ORA-04065 or ORA-06508 underneath. Two details matter in production. First, it fires exactly once per affected session: the next call re-initialises the package and works. Second, it does not roll back your transaction. Only the failing call errors out; earlier uncommitted DML is still pending until your code commits or rolls back. Sessions that never touched the package, and packages with no package-level state at all, are unaffected. That's why it looks random.

package_state_demo.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- io.thecodeforge — Database tutorial
-- A package with session state: g_calls lives in each session's memory
CREATE OR REPLACE PACKAGE order_pkg AS
  PROCEDURE place_order(p_amount NUMBER);
END order_pkg;
/
CREATE OR REPLACE PACKAGE BODY order_pkg AS
  g_calls PLS_INTEGER := 0;   -- package-level variable = session state
  PROCEDURE place_order(p_amount NUMBER) IS
  BEGIN
    g_calls := g_calls + 1;
    DBMS_OUTPUT.PUT_LINE('Order ' || p_amount || ' (call ' || g_calls || ')');
  END;
END order_pkg;
/

-- Session 1
EXEC order_pkg.place_order(100);

-- Session 2 recompiles the body (a deploy):
--   ALTER PACKAGE order_pkg COMPILE BODY;

-- Session 1 again: first call fails, second works
EXEC order_pkg.place_order(200);
EXEC order_pkg.place_order(200);
Output
Order 100 (call 1)
ORA-04068: existing state of packages has been discarded
ORA-04061: existing state of package body "APP.ORDER_PKG" has been invalidated
ORA-04065: not executed, altered or dropped package body "APP.ORDER_PKG"
ORA-06508: PL/SQL: could not find program unit being called: "APP.ORDER_PKG"
Order 200 (call 1)
⚠ Production Trap:
ORA-04068 does not roll back the transaction, but many application error handlers do. Decide deliberately: either retry just the failed call inside the same transaction, or roll back and retry the whole unit of work. Never swallow the error.

ORA-04063: When Your Package Won't Even Compile

ORA-04063 means the object you called is INVALID: it has compilation errors, so Oracle refuses to run it. It names the object but not the line. It usually appears after a deployment in which something the package depends on changed: a column was renamed or dropped, a referenced package's spec changed, or a grant was revoked. Oracle marks the dependent package INVALID and tries to recompile it on the next call. If that compile fails, every caller gets ORA-04063. Unlike ORA-04068, retrying never helps. The fix is always: read the compile errors, fix the cause, recompile. Remember that the cause is often not in the package's own code, but in an object it depends on.

ora04063_diagnose.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
-- io.thecodeforge — Database tutorial
-- The ORDERS table no longer has an AMOUNT column (renamed to TOTAL)
CREATE OR REPLACE PACKAGE BODY order_pkg AS
  PROCEDURE place_order(p_amount NUMBER) IS
  BEGIN
    INSERT INTO orders (order_id, amount) VALUES (order_seq.NEXTVAL, p_amount);
  END;
END order_pkg;
/

-- Every caller now fails
EXEC order_pkg.place_order(100);

-- Read the real error
SHOW ERRORS PACKAGE BODY order_pkg

-- Fix the code (amount -> total), then recompile
ALTER PACKAGE order_pkg COMPILE BODY;
Output
Warning: Package Body created with compilation errors.
ORA-04063: package body "APP.ORDER_PKG" has errors
ORA-06508: PL/SQL: could not find program unit being called: "APP.ORDER_PKG"
LINE/COL ERROR
-------- -----------------------------------------------
4/5 PL/SQL: SQL Statement ignored
4/43 PL/SQL: ORA-00904: "AMOUNT": invalid identifier
Package body altered.
💡Senior Shortcut:
Query USER_ERRORS directly to get the full error text without SQL*Plus formatting: SELECT line, position, text FROM user_errors WHERE name = 'ORDER_PKG' AND type = 'PACKAGE BODY' ORDER BY sequence;

The Deployment Pattern Behind Most ORA-04068

Almost every ORA-04068 incident has the same shape: a stateful package is recompiled while a connection pool is holding long-lived sessions that have already used it. Each of those sessions fails exactly once, spread over the next few minutes as the pool hands them out. Note that a recompile doesn't only come from your own deploy. Changing anything the package depends on, such as a table, a view or another package's spec, invalidates it, and Oracle recompiles it automatically on the next call. There are three reliable fixes. You can deploy in a window and recycle the pool, so no session carries old state. You can remove package-level state from hot packages, so there's nothing to discard. Or you can use Edition-Based Redefinition (EBR), where new code goes into a new edition: sessions already connected keep using the old edition, and new sessions pick up the new one. EBR is available in every Oracle edition, but it needs schema preparation: editions enabled for the owner, and editioning views over the tables.

ebr_deploy.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- io.thecodeforge — Database tutorial
-- One-time setup (as a DBA): allow the app owner to have editioned objects
ALTER USER app ENABLE EDITIONS;

-- Each release: create a new edition and compile the new code there
CREATE EDITION rel_42 AS CHILD OF ora$base;
ALTER SESSION SET EDITION = rel_42;

CREATE OR REPLACE PACKAGE BODY app.order_pkg AS
  -- new version
  ...
END order_pkg;
/

-- Make the new edition the default for NEW sessions.
-- Sessions already connected keep running the old code: no ORA-04068.
ALTER DATABASE DEFAULT EDITION = rel_42;
Output
User altered.
Edition created.
Session altered.
Package body created.
Database altered.
🔥Interview Gold:
EBR avoids ORA-04068 because a session's code never changes underneath it: the edition is fixed for the life of the session. A pool recycle after deploy achieves the same thing more crudely, by replacing every session.

How to Handle ORA-04068 in Application Code

You can't stop someone else's deploy from discarding state, but you can make the application shrug it off. Because ORA-04068 fires only once per session, a single retry of the same call on the same connection succeeds: that first failure is what re-initialises the package. Retry only on error code 4068, and only once. If the retry fails too, something else is wrong, such as ORA-04063, and you should surface it. Think about the transaction. The failed call didn't roll anything back, so retrying just that call inside the same transaction is safe. If your framework rolls back on any SQLException, retry the whole unit of work instead. The retry has one limit: after a retry the package state starts fresh. If your logic depended on values cached in package variables earlier in the session, they're gone, which is another reason to keep hot packages stateless.

OrderService.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// io.thecodeforge — Database tutorial
import java.sql.*;

public class OrderService {
    private final Connection conn;

    public OrderService(Connection conn) {
        this.conn = conn;
    }

    public void placeOrder(int amount) throws SQLException {
        int retries = 1;
        while (true) {
            try (CallableStatement stmt = conn.prepareCall("{call order_pkg.place_order(?)}")) {
                stmt.setInt(1, amount);
                stmt.execute();
                return; // success
            } catch (SQLException e) {
                // ORA-04068: existing state of packages has been discarded
                if (e.getErrorCode() == 4068 && retries-- > 0) {
                    // Retry once: package state will be reinitialized
                    continue;
                }
                throw e;
            }
        }
    }
}
Output
// First call after a deploy: ORA-04068 caught, retried once on the same connection, succeeds.
⚠ Never Do This:
Don't catch ORA-04068 and carry on as if the call had run. The call did not execute. Retry it, or propagate the error.

Diagnosing ORA-04063: It's Not Always Your Package

When ORA-04063 names a package that you didn't touch, look at what it depends on. If any object it references changes or becomes invalid, the package is invalidated too, and the failure cascades up the dependency chain. Start with the errors of the named object in USER_ERRORS. They usually name the real culprit: a missing column, a changed function signature, or a missing grant. Then list INVALID objects and their dependencies. To recompile, don't write a loop of ALTER statements. Package bodies need ALTER PACKAGE ... COMPILE BODY, and getting the order right by hand is error-prone. Use UTL_RECOMP or DBMS_UTILITY.COMPILE_SCHEMA, which compile in dependency order. Be aware that recompiling stateful packages will itself cause ORA-04068 in live sessions, so do it in the same deploy window.

dependency_chain.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
-- io.thecodeforge — Database tutorial
-- What is invalid right now?
SELECT object_name, object_type, last_ddl_time
FROM   user_objects
WHERE  status = 'INVALID'
ORDER  BY last_ddl_time DESC;

-- The real compile errors
SELECT name, type, line, position, text
FROM   user_errors
ORDER  BY name, type, sequence;

-- What does ORDER_PKG depend on?
SELECT referenced_name, referenced_type
FROM   user_dependencies
WHERE  name = 'ORDER_PKG';

-- Recompile only invalid objects, in dependency order
EXEC DBMS_UTILITY.COMPILE_SCHEMA(schema => USER, compile_all => FALSE);
Output
OBJECT_NAME OBJECT_TYPE LAST_DDL_TIME
------------ ------------- -------------------
ORDER_PKG PACKAGE BODY 2026-10-27 12:09:58
NAME TYPE LINE POSITION TEXT
--------- ------------ ---- -------- ---------------------------------
ORDER_PKG PACKAGE BODY 4 43 PL/SQL: ORA-00904: "AMOUNT": invalid identifier
REFERENCED_NAME REFERENCED_TYPE
--------------- ---------------
ORDERS TABLE
ORDER_SEQ SEQUENCE
PL/SQL procedure successfully completed.
💡Production Trap:
A dropped or revoked grant also produces ORA-04063 downstream. If USER_ERRORS shows ORA-00942 or PLS-00201 for an object that exists, check the grants before touching the code.

Make Hot Packages Stateless (and Where SERIALLY_REUSABLE Fits)

The most durable fix is to give ORA-04068 nothing to discard. A package with no package-level variables, constants or cursors has no session state, and recompiling it doesn't raise ORA-04068 in other sessions. Move cached values into a function that queries the source, into an application context (SYS_CONTEXT), or into a table. Pass anything else as parameters. PRAGMA SERIALLY_REUSABLE is the other option. It keeps package state only for the duration of one server call, so there's nothing long-lived to invalidate. The cost is that variables reset on every call, and serially reusable packages can't be called from SQL statements. Use it for genuinely call-scoped state, not as a blanket fix.

stateless_package.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- io.thecodeforge — Database tutorial
-- BEFORE: cached in a package variable -> ORA-04068 after every deploy
CREATE OR REPLACE PACKAGE BODY tax_pkg AS
  g_region VARCHAR2(10);   -- session state
  FUNCTION region RETURN VARCHAR2 IS
  BEGIN
    IF g_region IS NULL THEN
      SELECT region INTO g_region FROM app_config;
    END IF;
    RETURN g_region;
  END;
END tax_pkg;
/

-- AFTER: no package-level state; recompiles no longer hit live sessions
CREATE OR REPLACE PACKAGE BODY tax_pkg AS
  FUNCTION region RETURN VARCHAR2 RESULT_CACHE IS
    l_region VARCHAR2(10);
  BEGIN
    SELECT region INTO l_region FROM app_config;
    RETURN l_region;
  END;
END tax_pkg;
/
Output
Package body created.
Package body created.
⚠ Watch Out:
Constants count as state too. A package whose only state is a constant can still raise ORA-04068 when recompiled. Put constants in a separate spec-only package that rarely changes.
● Production incidentPOST-MORTEMseverity: high

Midday Hotfix Broke 30% of Checkouts

Symptom
At 12:10 PM, during the lunch peak, roughly 30% of checkout attempts failed with ORA-04068. The application's error handler rolled back each failed checkout, so customers saw a payment error. Retrying in the browser usually worked.
Assumption
The team blamed a database failover or a network blip, because only some requests failed and retries succeeded. They spent 25 minutes in the network dashboards.
Root cause
A developer had compiled a hotfix into ORDER_PKG. The package body held a package-level variable caching the tax region. Every pooled connection that had already called ORDER_PKG lost that state, and its next call raised ORA-04068. Connections that had never called the package were unaffected, which is why it looked random.
Fix
Short term: a one-time retry on ORA-04068 around the checkout call, and a connection-pool recycle after any package deploy. Long term: the cached tax region moved into a lookup function with no package-level state, and package deploys moved to Edition-Based Redefinition.
Key lesson
  • ORA-04068 isn't random: it hits every session that used the package before the recompile, exactly once.
  • Remove package-level state from hot packages, or deploy them in a way that doesn't touch live sessions.
Production debug guideSystematic recovery paths for the failure modes engineers actually hit.3 entries
Symptom · 01
ORA-04068 with ORA-04061 / ORA-04065 / ORA-06508 after a deploy
→
Fix
1. Find the recompiled package: USER_OBJECTS ordered by LAST_DDL_TIME. 2. Confirm it is VALID. 3. Add a single retry on error 4068, or recycle the connection pool. 4. Long term: remove package-level state, or adopt EBR.
Symptom · 02
ORA-04063 when calling a package
→
Fix
1. Query USER_ERRORS for the object. 2. Fix the reported cause (a missing column, a changed signature, a revoked grant). 3. Recompile with DBMS_UTILITY.COMPILE_SCHEMA(USER, FALSE). 4. Re-check that the INVALID count is zero.
Symptom · 03
ORA-04068 with no deploy on record
→
Fix
Something the package depends on changed (a table, a view, another spec), so Oracle recompiled it automatically. Check LAST_DDL_TIME on its dependencies in USER_DEPENDENCIES.
★ ORA-04068 / ORA-04063 Triage Cheat SheetFirst-response commands for when things go wrong — copy-paste ready.
ORA-04068: existing state of packages has been discarded−
Immediate action
Find what was recompiled in the last hour.
Commands
SELECT object_name, object_type, status, last_ddl_time FROM user_objects WHERE last_ddl_time > SYSDATE - 1/24 ORDER BY last_ddl_time DESC;
SELECT referenced_name, referenced_type FROM user_dependencies WHERE name = 'ORDER_PKG';
Fix now
Retry the call once, or recycle the connection pool.
ORA-04063: package body "SCHEMA.PKG" has errors+
Immediate action
Read the real compile errors.
Commands
SELECT line, position, text FROM user_errors WHERE name = 'ORDER_PKG' ORDER BY sequence;
SELECT object_name, object_type FROM user_objects WHERE status = 'INVALID';
Fix now
Fix the cause, then EXEC DBMS_UTILITY.COMPILE_SCHEMA(USER, FALSE);
ORA-04068 after every deployment+
Immediate action
Find the package-level state.
Commands
SELECT name, line, text FROM user_source WHERE type IN ('PACKAGE','PACKAGE BODY') AND REGEXP_LIKE(text, '^\s*g_', 'i');
SELECT editions_enabled FROM dba_users WHERE username = 'APP';
Fix now
Make hot packages stateless, or move releases onto Edition-Based Redefinition.
Feature / AspectORA-04068ORA-04063
Error messageexisting state of packages has been discardedpackage body "SCHEMA.PKG" has errors
Is the package valid?Yes. Only the session's copy of its state is goneNo. It is INVALID and won't run
CausePackage recompiled after this session used itCompile errors, often from a changed dependency
Transaction impactThe failing call errors; no automatic rollbackThe failing call errors; no automatic rollback
Does a retry help?Yes. Exactly once per sessionNever, until the code compiles
PreventionStateless packages, pool recycle, EBRCompile and test against the target schema before deploy
⚙ Quick Reference
6 commands from this guide
FileCommand / CodePurpose
package_state_demo.sqlCREATE OR REPLACE PACKAGE order_pkg ASWhy Oracle Discards Package State (And Why It's Not a Bug)
ora04063_diagnose.sqlCREATE OR REPLACE PACKAGE BODY order_pkg ASORA-04063
ebr_deploy.sqlALTER USER app ENABLE EDITIONS;The Deployment Pattern Behind Most ORA-04068
OrderService.javapublic class OrderService {How to Handle ORA-04068 in Application Code
dependency_chain.sqlSELECT object_name, object_type, last_ddl_timeDiagnosing ORA-04063
stateless_package.sqlCREATE OR REPLACE PACKAGE BODY tax_pkg ASMake Hot Packages Stateless (and Where SERIALLY_REUSABLE Fit

Key takeaways

1
ORA-04068 fires once per session that used a package before it was recompiled. The package is valid, and the next call works.
2
It does not roll back the transaction. Only the failing call errors out.
3
ORA-04063 means the object is INVALID. Read USER_ERRORS and fix the cause, which is often a changed dependency or a revoked grant.
4
Prevent ORA-04068 with stateless hot packages, a pool recycle after deploys, or Edition-Based Redefinition.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
How does Oracle handle package state when a package is recompiled, and w...
Q02SENIOR
When would you choose Edition-Based Redefinition over a maintenance wind...
Q03SENIOR
ORA-04068 hits mid-transaction. Has the transaction been rolled back, an...
Q04JUNIOR
What is the difference between ORA-04068 and ORA-04063?
Q05SENIOR
You deploy a package change and immediately see ORA-04068 across multipl...
Q06SENIOR
How would you design a deployment pipeline for PL/SQL packages to avoid ...
Q01 of 06SENIOR

How does Oracle handle package state when a package is recompiled, and why does it cause ORA-04068?

ANSWER
Package-level variables, constants and cursors are instantiated per session. When the package is recompiled, Oracle can't map old state to new code, so it discards it. The next call from a session that held state raises ORA-04068, which re-initialises the package, so the call after that works. Sessions that never used the package, and packages with no state, are unaffected.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
How do I fix ORA-04068?
02
What's the difference between ORA-04068 and ORA-04063?
03
Does ORA-04068 roll back my transaction?
04
Why do I get ORA-04068 when nobody deployed anything?
05
How do I see the errors behind ORA-04063?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
✓ Verified
production tested
October 27, 2026
last updated
2,087
articles · all by Naren
🔥

That's PL/SQL. Mark it forged?

3 min read · try the examples if you haven't

←
Previous
PyMySQL 2003 Cant Connect Fix
28 / 28 · PL/SQL