# Resolving ORA-04061: A Practical Guide to PL/SQL Package Invalidation

- Link: https://ultimasolution.pl/fix-ora-04061-package-state/
- Published: 2026-04-10T09:05:43+02:00
- Author: Karol Preiskorn

## Sources and further reading

 * [Oracle PL/SQL Packages](https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/plsql-packages.html)—
   package state, initialization, and `SERIALLY_REUSABLE`.
 * [Oracle Database error reference for ORA-04061](https://docs.oracle.com/error-help/db/ora-04061/).

Use the Oracle documentation for version-specific behavior; test package changes
in a representative session and connection-pool setup before production deployment.

**Short answer:** ORA-04061 means that Oracle invalidated the state of a PL/SQL 
package while the current session still held an instance of it. It commonly appears
with ORA-04068, ORA-04065, and ORA-06508 after a package, dependency, synonym, type,
or table change.

## ORA-04061 and the related error chain

The messages below describe different parts of the same failure. The exact wording
can vary by Oracle version, but the complete stack is more useful than the first
line alone.

 * **ORA-04061:** the existing state of a package has been invalidated.
 * **ORA-04068:** Oracle discarded the existing package state.
 * **ORA-04065:** the altered or dropped package could not be executed.
 * **ORA-06508:** Oracle could not find the program unit being called.

    ```EnlighterJSRAW
    ORA-04068: existing state of packages has been discarded
    ORA-04061: existing state of package body "SCHEMA.PACKAGE" has been invalidated
    ORA-04065: not executed, altered or dropped package body "SCHEMA.PACKAGE"
    ORA-06508: PL/SQL: could not find program unit being called: "SCHEMA.PACKAGE"
    ```

## What ORA-04061 means

A package becomes stateful when its specification or body contains package-level
variables, constants, or cursors. Once a session has instantiated that package, 
recompiling it or invalidating one of its dependencies makes the existing in-memory
state unsafe. Oracle discards that state and raises the error on the next reference
instead of continuing with stale values.

## Typical triggers

 * Deploying or recompiling a package specification or body while sessions are still
   using it.
 * Changing a dependent table, view, type, synonym, or referenced package.
 * Running DDL from a migration job while application connection-pool sessions remain
   open.
 * Keeping request-specific state in package-level variables or cursors.

## Safe recovery

 1. Capture the complete error stack and identify the package named in ORA-04061, ORA-
    04065, or ORA-06508.
 2. Check whether a deployment or dependency change occurred at the same time.
 3. Confirm whether the original transaction committed, rolled back, or is still open
    before retrying.
 4. Retry only when the operation is idempotent or its transaction outcome is known.
    Do not blindly repeat an order, payment, message, or migration operation.
 5. If the error persists, recycle the affected application session or connection-pool
    connection according to your change procedure. Do not restart the database as a
    first response.
 6. Check invalid objects and dependencies before recompiling more objects in production.

## Connection-pool incident example

A common production sequence looks like this:

 1. Application connection A calls `APP_SESSION_PKG` and creates package state.
 2. A deployment recompiles the package or one of its dependencies.
 3. Connection A remains open in the pool and is returned to the application.
 4. The next request reuses connection A and receives ORA-04061 followed by ORA-04068.
 5. The pool must discard or refresh that connection before the application can safely
    continue.

Refreshing a connection does not repair an incorrect deployment or a broken dependency.
Treat it as recovery for the affected session, then investigate the database objects
and deployment order.

## Find the invalid object and dependencies

    ```EnlighterJSRAW
    SELECT owner,
           object_name,
           object_type,
           status
    FROM all_objects
    WHERE owner = UPPER(:owner)
      AND status <> 'VALID'
    ORDER BY object_type, object_name;
    ```

    ```EnlighterJSRAW
    SELECT owner,
           name,
           type,
           referenced_owner,
           referenced_name,
           referenced_type
    FROM all_dependencies
    WHERE referenced_owner = UPPER(:package_owner)
      AND referenced_name = UPPER(:package_name)
    ORDER BY owner, name, type;
    ```

## Find package-level state with PL/Scope

Enable PL/Scope in a controlled schema-owner session and recompile the package bodies
before querying identifier metadata:

    ```EnlighterJSRAW
    ALTER SESSION SET plscope_settings = 'IDENTIFIERS:ALL';
    ```

    ```EnlighterJSRAW
    SELECT object_name AS package_name,
           object_type,
           name AS identifier_name,
           type,
           usage
    FROM user_identifiers
    WHERE object_type IN ('PACKAGE', 'PACKAGE BODY')
      AND usage = 'DECLARATION'
      AND type IN ('VARIABLE', 'CONSTANT', 'CURSOR')
    ORDER BY object_name, object_type, name;
    ```

Review the output for state that should be local to a procedure or function. PL/
Scope output is diagnostic metadata; it does not prove that a package is safe to
change without testing its callers.

## A stateful package example

    ```EnlighterJSRAW
    CREATE OR REPLACE PACKAGE BODY mypkg IS
      g_state NUMBER := 5;

      PROCEDURE myproc IS
        l_value NUMBER;
      BEGIN
        SELECT x INTO l_value FROM dependonme;
        l_value := l_value * g_state;
        DBMS_OUTPUT.PUT_LINE('My result is: ' || l_value);
      END myproc;
    END mypkg;
    /
    ```

`g_state` belongs to the package instance, not to one call. Prefer local variables
for request-specific data. `SERIALLY_REUSABLE` is not a universal fix: it changes
package-state lifetime and can break code that expects state to survive between 
calls in the same session.

## Preventing recurrence

 * Schedule package and dependency changes with a controlled deployment window.
 * Coordinate DDL with application connection pools and recycle affected sessions
   when required.
 * Keep package state minimal and document initialization and reset behavior.
 * Make retry logic explicit and idempotent; never hide a failed transaction behind
   an automatic retry.
 * After deployment, monitor the full ORA-04068/ORA-04061/ORA-06508 chain rather
   than only the first message.

### Production checklist

 * Capture the complete error stack.
 * Identify the changed package and dependency.
 * Confirm the transaction outcome.
 * Check invalid objects and dependencies.
 * Test the package with a new session.
 * Recycle affected connection-pool sessions.
 * Verify deployment order and post-deployment health.

## Frequently asked questions

### Is ORA-04061 a data-corruption error?

Usually it indicates invalid package state rather than data corruption. The failed
transaction still must be checked because the application may have performed part
of its work before the exception.

### Can I fix ORA-04061 by retrying?

Sometimes a new package instance resolves the error, but retry only when the operation
is safe and idempotent. For payments, orders, messages, and migrations, verify the
transaction outcome first.

### Do I need to restart the Oracle database?

Usually not. Recycle the affected application session or connection-pool connection
after confirming the deployment and transaction state. A database restart does not
correct invalid dependencies or an incorrect deployment.

### What is the difference between ORA-04061 and ORA-04068?

ORA-04061 identifies the invalidated package state. ORA-04068 reports that Oracle
discarded the existing package state. They commonly occur together.

### When should I contact a DBA?

Escalate when the error repeats after session recycling, invalid objects continue
to appear, the package is shared by many applications, or the failed operation changes
data. Preserve the deployment timestamp, package name, complete stack, session and
pool context, and diagnostic query results.

## ORA-04061 at a glance

**Cause:** Oracle invalidated a stateful PL/SQL package while the session still 
held its previous package instance.

**First response:** identify the changed package or dependency, protect the transaction,
and retry only when the operation is safe to repeat. If needed, recycle the affected
pooled session instead of restarting the database.

**Prevention:** reduce package-level state, coordinate DDL with connection pools,
and test deployment-time invalidation with realistic sessions.

### In this guide

 * [The ORA-04061 error chain](https://ultimasolution.pl/fix-ora-04061-package-state/#ora-04061-error-chain)
 * [Safe recovery and connection-pool handling](https://ultimasolution.pl/fix-ora-04061-package-state/#ora-04061-recovery)
 * [Diagnostics and PL/Scope](https://ultimasolution.pl/fix-ora-04061-package-state/#ora-04061-diagnostics)
 * [Prevention checklist](https://ultimasolution.pl/fix-ora-04061-package-state/#ora-04061-prevention)
 * [Frequently asked questions](https://ultimasolution.pl/fix-ora-04061-package-state/#ora-04061-faq)
