When Oracle JVM breaks, it rarely announces itself clearly. You get cascading invalid package errors, PL/SQL wrappers that suddenly fail to compile, or Java stored procedures returning cryptic ORA-29549 and ORA-29553 errors. This guide covers the full recovery sequence — from verifying prerequisites through reinstalling the JVM itself to restoring all dependent objects and validating the result.
Written against Oracle Database 11.2.0.3. Notes for 19c / 21c are included where the procedure differs. All steps run as DBA in SQL*Plus unless stated otherwise.
Before you start: Take a cold backup or export if at all possible. The JVM reinstallation procedure restarts the database in restricted mode and replaces core system objects. It is not reversible without a restore.
Recovery Sequence Overview
Work through the phases in order. Each phase is a prerequisite for the next — do not skip ahead if you find failures.
| Phase | What it covers | Required if |
|---|---|---|
| 1 | Restore CATPROC | CATPROC status is not VALID in DBA_REGISTRY |
| 2 | Reinstall JVM | JAVAVM or CATJAVA is missing or INVALID |
| 3 | Restore DBMS_CRYPTO grants | After any JVM reinstall, or when Java crypto calls fail |
| 4 | Restore external directory | After JVM reinstall, or when directory objects are missing |
| 5 | Restore Java schema user | Java user account is locked, missing, or has lost privileges |
| 6 | Reinstall custom Java objects | Application Java classes are invalid or missing |
| 7 | Functional test | Always — run after every recovery |
Phase 1 — Restore CATPROC
CATPROC (Oracle Database Packages and Types) is a hard dependency of JVM. If it is invalid, the JVM reinstallation scripts will fail partway through. Fix it first.
Check its current status:
SELECT comp_id, comp_name, status
FROM dba_registry
WHERE comp_id = 'CATPROC';
If status is not VALID, proceed with the two-step fix below.
Step 1 — Recompile invalid objects
This is the quick path. utlrp.sql recompiles all invalid objects across the database in parallel. It resolves many CATPROC invalidity issues caused by incomplete patches or interrupted upgrades.
@$ORACLE_HOME/rdbms/admin/utlrp.sql
Re-check DBA_REGISTRY after completion. If CATPROC is now VALID, proceed to Phase 2. If still invalid, continue to Step 2.
Step 2 — Reinstall catalog and packages
This rebuilds the data dictionary catalog and all core PL/SQL packages from scratch. It takes significant time on large databases and will report many objects being replaced — that is expected.
@$ORACLE_HOME/rdbms/admin/catalog.sql
@$ORACLE_HOME/rdbms/admin/catproc.sql
@$ORACLE_HOME/rdbms/admin/utlrp.sql
Oracle 19c / 21c note: The scripts and procedure are identical. In a CDB environment, connect to
CDB$ROOTasSYSDBAbefore running these — they operate at the container level and will apply across PDBs appropriately.
Phase 2 — Reinstall Oracle JVM
This is the core of the recovery. The procedure mounts the database, disables several background processes that would interfere with JVM replacement, recreates the Java system layer, and then runs the full JVM initialisation scripts. The database must be restarted as part of this process.
This procedure restarts the database. Coordinate a maintenance window. All active sessions will be terminated.
Step 1 — Mount the database
Shut down the database first, then bring it to mount state — not open. The JVM replacement must happen before normal operations resume.
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
Step 2 — Prepare init parameters
Before opening the database, disable three settings that would otherwise interfere with JVM reinstallation: the JIT compiler (which would attempt to compile Java classes as they load), system triggers (which fire on DDL and would conflict with the Java system recreation), and job queue processes (which would spawn background jobs during the install).
ALTER SYSTEM SET java_jit_enabled = FALSE;
ALTER SYSTEM SET "_system_trig_enabled" = FALSE;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 0;
Step 3 — Open in restricted mode
Open the database but restrict access to DBA sessions only. This prevents any application connections from hitting the database while the JVM is being rebuilt.
ALTER DATABASE OPEN;
ALTER SYSTEM ENABLE RESTRICTED SESSION;
Step 4 — Recreate the Java system layer
This statement drops and recreates the entire Java system within Oracle. It is the equivalent of wiping and reinstalling the JVM engine itself. It will take several minutes and produces no output during execution — that is normal.
CREATE OR REPLACE JAVA SYSTEM;
/
After it completes, verify the Java object table to confirm the system layer is present:
SELECT obj#, name
FROM obj$
WHERE type# IN (28, 29, 30)
OR namespace = 32;
You should see thousands of rows. An empty result or very few rows means the CREATE OR REPLACE JAVA SYSTEM did not complete successfully — check the alert log before continuing.
Step 5 — Run JVM initialisation scripts
These scripts install all JVM components in the correct dependency order. Run them sequentially and do not interrupt. Each script may take several minutes.
-- Core JVM
@$ORACLE_HOME/javavm/install/initjvm.sql
-- Oracle XML with Java support
@$ORACLE_HOME/xdk/admin/initxml.sql
@$ORACLE_HOME/xdk/admin/xmlja.sql
-- Java catalog packages
@$ORACLE_HOME/rdbms/admin/catjava.sql
-- Expression Filter (Oracle 11g only — see note below)
@$ORACLE_HOME/rdbms/admin/catexf.sql
Oracle 12c / 19c / 21c note:
catexf.sql(Expression Filter) was deprecated in 12c and the component does not exist in 19c/21c. Skip this script on any version from 12c onward — running it will produce errors.
Step 6 — Recompile all invalid objects
@$ORACLE_HOME/rdbms/admin/utlrp.sql
Step 7 — Reset init parameters and restart
Restore the three parameters that were disabled before the install, then perform a clean shutdown and normal startup.
ALTER SYSTEM SET java_jit_enabled = TRUE;
ALTER SYSTEM SET "_system_trig_enabled" = TRUE;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES = 10;
SHUTDOWN IMMEDIATE;
Start the database normally (outside SQL*Plus if using OS-managed startup, or via SQL*Plus):
STARTUP;
Step 8 — Verify JVM is restored
SELECT comp_id, comp_name, status
FROM dba_registry
WHERE comp_id IN ('JAVAVM', 'CATJAVA');
SELECT count(*), object_type, status
FROM all_objects
WHERE object_type LIKE '%JAVA%'
GROUP BY object_type, status
ORDER BY object_type;
Both JAVAVM and CATJAVA must be VALID, and the object counts should match the reference values from the oracle jvm diagnostics guide (SYS: ~20,500 JAVA CLASS on 11.2.0.3).
Oracle 19c / 21c — Multitenant note: In a CDB environment, JVM reinstallation for a PDB requires connecting directly to the target PDB as
SYSDBAand runninginitjvm.sqlandcatjava.sqlwithin that PDB context. TheCREATE OR REPLACE JAVA SYSTEMcommand must also be run within the PDB. Modifying_system_trig_enabledis a CDB-level operation — set it fromCDB$ROOTbefore opening the PDB.
Phase 3 — Restore DBMS_CRYPTO Grants
JVM reinstallation does not always preserve all privilege grants on system packages. DBMS_CRYPTO is a common casualty — any application code using Java cryptography or calling DBMS_CRYPTO directly from non-SYS schemas will fail if the public execute grant is missing.
Check whether the grant exists:
SELECT owner, table_name, grantee, privilege
FROM dba_tab_privs
WHERE owner = 'SYS'
AND table_name = 'DBMS_CRYPTO'
AND grantee = 'PUBLIC'
AND privilege = 'EXECUTE';
If no rows are returned, restore the grant:
GRANT EXECUTE ON SYS.DBMS_CRYPTO TO PUBLIC;
Security note: Granting
DBMS_CRYPTOexecute toPUBLICis appropriate in environments where all database users are trusted application accounts. In multi-tenant or shared environments, consider granting only to specific roles or users rather than PUBLIC.
Phase 4 — Restore External Directory
Oracle directory objects are database-level pointers to filesystem paths. They are used for external tables, log file output, and Java I/O operations. After a JVM reinstall or database rebuild, these objects may need to be recreated.
Step 1 — Verify the filesystem path exists
ls -la /opt/oracle/admin/<db_name>/external_tables/
# Create it if missing:
mkdir -p /opt/oracle/admin/<db_name>/external_tables/
chown oracle:oinstall /opt/oracle/admin/<db_name>/external_tables/
Step 2 — Recreate the Oracle directory object
-- Check if it already exists
SELECT directory_name, directory_path
FROM all_directories
WHERE owner = 'SYS';
-- Create or replace if missing/incorrect
CREATE OR REPLACE DIRECTORY LOG_DIR
AS '/opt/oracle/admin/<db_name>/external_tables';
-- Grant access to the appropriate user or role
GRANT READ, WRITE ON DIRECTORY LOG_DIR TO PUBLIC;
Note: Replace
<db_name>with your actual database name. Adjust the path and directory name to match your environment. Review which schemas actually need access before granting toPUBLIC.
Phase 5 — Restore the Java Schema User
If your application loads Java into a dedicated schema user (the standard pattern for keeping application Java separate from SYS), that user’s account and privileges need to be verified after any JVM recovery. A locked account or missing role grant will cause all Java calls from that schema to fail immediately.
Step 1 — Create or unlock the user
-- Check if user exists and is open
SELECT username, account_status
FROM dba_users
WHERE username = 'JAVA_OBJS';
-- Create if missing
CREATE USER java_objs IDENTIFIED BY <password>
DEFAULT TABLESPACE <tablespace_name>;
ALTER USER java_objs QUOTA UNLIMITED ON <tablespace_name>;
-- Unlock if locked
ALTER USER java_objs ACCOUNT UNLOCK;
ALTER USER java_objs IDENTIFIED BY <password>;
Step 2 — Restore role grants
-- Check existing role grants
SELECT granted_role
FROM dba_role_privs
WHERE grantee = 'JAVA_OBJS';
-- Restore required roles
GRANT JAVASYSPRIV TO java_objs;
GRANT CONNECT TO java_objs;
Oracle 18c / 19c / 21c note: The
JAVA_DEPLOYrole was deprecated in Oracle Database 18c. Do not grant it on 18c and later — it no longer exists. On 11g and earlier, it was required to deploy Java stored procedures vialoadjava.
Step 3 — Restore system privileges
-- Check existing system privileges
SELECT privilege
FROM dba_sys_privs
WHERE grantee = 'JAVA_OBJS';
-- Restore required privileges
GRANT CREATE PROCEDURE TO java_objs;
GRANT CREATE TABLE TO java_objs;
Phase 6 — Reinstall Custom Java Objects
After the JVM itself is restored and the schema user is in place, any application Java classes that were loaded into the database need to be redeployed. The general pattern is: drop the old objects, load from the JAR, compile sources, resolve classes, recreate PL/SQL wrapper functions, and re-grant execute privileges.
Step 1 — Drop existing Java objects from the schema
Run from the OS as the Oracle OS user. dropjava removes all Java classes, sources, and resources that were loaded from a given JAR.
dropjava -v -u java_objs/<password> /path/to/your-application.jar
Step 2 — Load the JAR
loadjava -u java_objs/<password> -resolve /path/to/your-application.jar -grant public
The -resolve flag forces Oracle to verify all class dependencies during load rather than deferring them. Load errors are much easier to diagnose at this stage than at runtime. The -grant public flag makes the loaded classes accessible to all schemas — scope this down if your application does not require public access.
Step 3 — Compile sources and resolve classes
If your JAR includes Java source files (not just compiled classes), compile them explicitly. Then resolve all classes to confirm dependencies are satisfied.
-- Compile Java sources (if applicable)
ALTER JAVA SOURCE "java_objs"."com/example/YourClass" COMPILE;
-- Resolve Java classes
ALTER JAVA CLASS "java_objs"."com/example/YourClass" RESOLVE;
Verify that everything loaded cleanly:
SELECT object_name, object_type, status
FROM all_objects
WHERE owner = 'JAVA_OBJS'
AND object_type LIKE '%JAVA%'
ORDER BY object_type, object_name;
All rows must show VALID. Any INVALID rows indicate unresolved dependencies or compilation errors — check USER_ERRORS for detail.
Step 4 — Recreate PL/SQL wrapper functions
Java stored procedures are called through thin PL/SQL wrapper functions that map SQL types to Java types. These need to be recreated if the schema was rebuilt.
-- Example wrapper pattern
CREATE OR REPLACE FUNCTION java_objs.your_function(input VARCHAR2)
RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'com.example.YourClass.yourMethod(java.lang.String) return java.lang.String';
/
-- Grant access to the wrappers
GRANT EXECUTE ON java_objs.your_function TO PUBLIC;
-- Create public synonym for schema-transparent access
CREATE PUBLIC SYNONYM your_function FOR java_objs.your_function;
Oracle 19c / 21c note: The
loadjavaanddropjavautilities still exist but are deprecated in 19c and later in favour ofDBMS_JAVA.loadjavaandDBMS_JAVA.dropjavaPL/SQL APIs. Both approaches work in 19c/21c. For new deployments on 19c+, prefer the PL/SQL API as the OS utilities may be removed in a future release.
Phase 7 — Functional Test
Do not close the maintenance window until you have confirmed that Java execution works end-to-end, not just that objects are VALID in the data dictionary.
Test 1 — Confirm JVM components are valid
SELECT comp_id, comp_name, status
FROM dba_registry
WHERE comp_id IN ('JAVAVM', 'CATJAVA', 'CATPROC');
All three must be VALID.
Test 2 — Confirm Java object counts
SELECT owner, object_type, status, COUNT(*)
FROM all_objects
WHERE object_type LIKE '%JAVA%'
GROUP BY owner, object_type, status
ORDER BY owner, object_type;
SYS should show approximately 20,500 JAVA CLASS objects (11.2.0.3). All rows should be VALID — any INVALID rows in SYS require another pass of utlrp.sql or a repeated JVM install.
Test 3 — Execute Java from SQL
Call one of your application’s Java wrapper functions directly from SQL. This confirms the full execution path: SQL engine → PL/SQL wrapper → Java class resolution → JVM execution → return value.
SELECT your_function('test_input') FROM dual;
A clean return value confirms success. An ORA-00904 (invalid identifier) means the synonym or wrapper function is missing. An ORA-29549 or ORA-29553 means the class is still invalid or the Java Pool is insufficient — refer to the diagnostics guide to investigate memory.
Test 4 — Confirm DBMS_JAVA is accessible
SELECT owner, object_name, object_type, status
FROM dba_objects
WHERE object_name = 'DBMS_JAVA'
ORDER BY owner, object_type;
Both SYS.DBMS_JAVA PACKAGE and SYS.DBMS_JAVA PACKAGE BODY must be VALID. A valid spec with an invalid body is a common post-install failure mode.
Common Failure Patterns and Fixes
| Symptom | Most likely cause | Action |
|---|---|---|
ORA-29549 — class has changed | Java class reloaded but old session state cached | Disconnect and reconnect all sessions; bounce the application connection pool |
ORA-29553 — class not found | Class invalid or Java Pool exhausted | Run Phase 6 again; check v$sgastat Java Pool free memory |
ORA-00904 — invalid identifier on wrapper call | Public synonym missing or pointing to wrong schema | Drop and recreate synonym; verify GRANT EXECUTE is in place |
utlrp.sql completes but JAVA CLASS objects remain INVALID | Unsatisfied class dependency — a referenced class is missing or also invalid | Run Phase 6 again with -resolve; check USER_ERRORS on the invalid objects |
initjvm.sql fails with ORA-01017 or privilege errors | Not running as SYSDBA, or restricted session not enabled | Confirm connection string uses / as sysdba; confirm RESTRICTED SESSION is active |
| JVM valid after recovery but broken again after next DB restart | Init parameters persisted incorrectly, or SPFILE not updated | Verify java_jit_enabled, JOB_QUEUE_PROCESSES, and _system_trig_enabled are reset with SCOPE=BOTH |
Summary
The full recovery sequence — CATPROC, JVM reinstall, package grants, directory objects, schema user, custom Java objects, functional test — is thorough but deterministic. Each phase has a clear success criterion before moving to the next. If you are scripting this for automation, the key checks to gate on are: DBA_REGISTRY status after each phase, and a live Java function call at the end that exercises the complete execution path.
Keep a copy of your loadjava commands, wrapper function DDL, and privilege grant statements in version control. A JVM recovery at 2 AM is significantly less painful when the reinstallation of custom objects is a single script rather than archaeology through change logs.