Tag: PATCHING

  • Oracle EBS R12.2 Multi-Node Patching in Downtime Mode: Recovering a Failed Slave Node with restart=yes

    Alhamdulillah, sharing another real patching session — this one from an Oracle E-Business Suite R12.2 multi-node environment. While applying a patch in downtime mode, I encountered an interesting situation: the patch completed successfully on the master node but failed on the slave node, while the final ADOP output still showed:

    adop exiting with status = 0 (Success)

    This post walks through the complete sequence: pre-checks, the slave-node failure, investigation, recovery using restart=yes, and the SQL checks used to verify the final patch state.

    Environment

    • Oracle E-Business Suite R12.2.13
    • AD/TXK Delta 15 (ADOP C.Delta.15)
    • Two application nodes: appsnode1 (master/admin node) and webnode1 (slave/web node)
    • Oracle Database 19c on dbnode1
    • Patch mode: downtime (single file system apply; no online patching cutover involved)

    Pre-Checks Before the Apply

    Before starting the patch, I checked three things: the current ADOP session status, application processes on all application nodes, and the current file-system edition.

    From the master node:

    [applmgr@appsnode1]$ adop -status
    Node Name Node Type Phase Status
    --------------- ---------- --------------- ---------------
    appsnode1 master APPLY ACTIVE
    CLEANUP NOT STARTED
    webnode1 slave APPLY ACTIVE
    CLEANUP NOT STARTED

    I also confirmed I was operating from the run edition:

    [applmgr@appsnode1]$ echo $FILE_EDITION
    run

    Then I checked for application-tier processes:

    [applmgr@appsnode1]$ ps -ef | egrep 'FNDLIBR|FNDSM|FNDCRM|FNDOPP|oacore|forms|WebLogic|NodeManager' | grep -v grep

    There was no output, confirming the expected services were down on the master node.

    Important: In a multi-node environment, repeat these process checks on every application node. Checking only the master node is not sufficient — a condition on a slave node can otherwise go unnoticed until the apply reaches it.

    Starting the Downtime Apply

    The downtime apply was initiated from the master node:

    [applmgr@appsnode1]$ adop phase=apply apply_mode=downtime patches=<patch_number>

    ADOP manages execution across the registered application-tier nodes, so there was no need to manually start ADOP on the slave node.

    During initialization, ETCC reported missing database fixes:

    [WARNING] ETCC: The following required database fixes have not been applied to node dbnode1:
    ...
    Refer to My Oracle Support Knowledge Document 1594274.1 for instructions.

    ETCC warnings should always be reviewed before proceeding. In this case, the apply was allowed to continue based on the maintenance plan, while the outstanding database fixes were documented and tracked separately for a subsequent maintenance activity.

    Master Succeeded, Slave Failed

    The patch application succeeded on the master node but failed on the slave:

    Applying <patch> patch(es) on admin node: [appsnode1].
    txkADOPEvalSrvStatus.pl returned SUCCESS
    Applying <patch> patch(es) on node(s): [webnode1].
    Running in Serial
    [ERROR] adop phase=apply failed on Node: "webnode1"
    Summary report for current adop session:
    Node webnode1: Failed
    - Apply status: Failed
    Node appsnode1: Completed successfully
    - Apply status: Completed successfully
    adop exiting with status = 0 (Success)

    This is an important operational lesson. Despite the slave-node failure being clearly reported in the summary, the ADOP invocation ended with adop exiting with status = 0 (Success).

    Therefore, relying only on the shell return code or the final ADOP exit line is not sufficient for determining whether every application node completed successfully. The per-node summary must also be reviewed.

    I confirmed the state with:

    adop -status -detail

    which showed:

    Node Name Node Type Phase Status
    --------------- ---------- --------------- ---------------
    appsnode1 master APPLY ACTIVE
    webnode1 slave APPLY FAILED

    For automated patching this matters even more: scripts should validate the ADOP session and per-node phase status rather than treating $? = 0 alone as proof of a successful multi-node patch.

    Investigating the Slave Node

    I then logged into webnode1. Application services were expected to be completely down, so I checked for NodeManager:

    [applmgr@webnode1]$ ps -ef | grep -i nodemanager | grep -v grep
    applmgr 4148261 1 0 Jun18 ... weblogic.NodeManager -v

    A NodeManager process was still running, and had been since a previous month.

    I checked whether other WebLogic or EBS application processes were present:

    [applmgr@webnode1]$ ps -ef | grep -i weblogic | grep -v grep

    Only the NodeManager process remained. Concurrent Manager processes were also absent:

    [applmgr@webnode1]$ ps -ef | grep FNDLIBR | grep -v grep

    No output was returned.

    Since the environment was in a planned patching outage and no managed servers were running, the stale NodeManager process was stopped:

    [applmgr@webnode1]$ kill 4148261

    I then verified again:

    [applmgr@webnode1]$ ps -ef | egrep 'FNDLIBR|FNDSM|oacore|forms|WebLogic|NodeManager' | grep -v grep

    No relevant processes remained.

    A Note About Root Cause

    The presence of the stale NodeManager was an abnormal condition that needed to be corrected before retrying the patch. However, unless the ADOP logs explicitly identify that process as the reason for the failure, it is safer not to state that NodeManager was definitively the root cause.

    What can be established from this incident is:

    1. The slave-node apply failed.
    2. A stale NodeManager process was discovered on that node.
    3. The process was stopped after confirming application services were intended to be down.
    4. The failed ADOP apply subsequently completed successfully with restart=yes.

    For a formal RCA, the relevant ADOP and slave-node logs should be used to establish the exact failure mechanism.

    Also, before terminating any process, verify that:

    • It belongs to the expected EBS environment/file system.
    • No managed servers depend on it.
    • Application services are intended to be down.
    • The action complies with your production change procedure.

    Recovering the Failed Apply with restart=yes

    After cleaning up the slave node, I returned to the master node. The existing failed apply was resumed using:

    [applmgr@appsnode1]$ adop phase=apply patches=<patch_number> apply_mode=downtime restart=yes

    ADOP detected the existing session:

    Checking for existing adop sessions.
    Application tier services are down.
    Continuing with the existing session [Session ID: <n>].

    The apply was then processed successfully:

    Applying <patch> patch(es) on admin node: [appsnode1].
    txkADOPEvalSrvStatus.pl returned SUCCESS
    Applying <patch> patch(es) on node(s): [webnode1].
    Running in Serial
    txkADOPEvalSrvStatus.pl returned SUCCESS

    The final summary showed both nodes successful:

    Summary report for current adop session:
    Node webnode1: Completed successfully
    - Apply status: Completed successfully
    Node appsnode1: Completed successfully
    - Apply status: Completed successfully

    The important point here is that I resumed the existing ADOP session rather than initiating an unrelated fresh patching attempt. The recovery command was executed from the master/admin node, allowing ADOP to coordinate processing on the registered slave node.

    For the exact semantics of restart=yes in downtime mode and multi-node processing, refer to the Oracle E-Business Suite Patching Guide and the relevant My Oracle Support documentation. What I can report from this incident is the observed behaviour above: ADOP continued the existing session and both nodes subsequently reported success.

    Post-Restart Validation

    After the successful rerun, I checked the detailed ADOP status:

    [applmgr@appsnode1]$ adop -status -detail

    The nodes no longer showed a failed apply state.

    I also scanned the latest ADOP logs:

    [applmgr@appsnode1]$ adopscanlog -latest=yes
    Scanning .../log/adop/<session>/ directory ...
    No Errors.

    adopscanlog is a useful quick check after an ADOP phase because it searches the session logs for reported errors that may otherwise be easy to miss.

    SQL Verification: Confirming Patch Registration

    I don’t rely only on the ADOP console output. After patching, I also verify the database-side patch records.

    1. Check AD_BUGS

    SET LINES 200
    COL BUG_NUMBER FORMAT A15
    COL CREATION_DATE FORMAT A22
    SELECT bug_number,
    creation_date
    FROM ad_bugs
    WHERE bug_number = '<patch_number>';

    This confirms whether the specified bug/patch number is recorded in AD_BUGS. Because patch contents and registration behaviour can vary, this check should be used together with ADOP status, logs, and the relevant applied-patch records rather than as standalone proof of complete patch application. Running the same query before patching is also useful, because it establishes a clear before-and-after state.

    2. Check Applied Patch Records

    SELECT applied_patch_id,
    patch_name,
    patch_type,
    source_code,
    creation_date,
    last_update_date,
    data_model_done_flag
    FROM ad_applied_patches
    WHERE patch_name = '<patch_number>';

    Depending on the patch structure, this helps confirm the corresponding patch-driver records.

    3. Verify AD/TXK Code Levels

    COL ABBREVIATION FORMAT A15
    COL CODELEVEL FORMAT A25
    SELECT abbreviation,
    codelevel
    FROM ad_trackable_entities
    WHERE abbreviation IN ('ad','txk')
    ORDER BY abbreviation;

    For this environment the query returned:

    ABBREVIATION CODELEVEL
    --------------- -------------------------
    ad C.15
    txk C.15

    This check is especially important when applying AD/TXK-related patches or preparing for an EBS Release Update Pack.

    4. Verify the EBS Release

    SELECT release_name
    FROM fnd_product_groups;

    Expected for this environment: 12.2.13.

    5. Verify Node Registration

    COL NODE_NAME FORMAT A25
    SELECT node_name,
    support_cp,
    support_forms,
    support_web,
    support_admin
    FROM fnd_nodes
    ORDER BY node_name;

    This provides a quick sanity check of application-tier node registration and responsibilities.

    6. Verify ADOP Valid Nodes

    SELECT *
    FROM adop_valid_nodes
    ORDER BY node_name;

    Both application nodes should appear as expected.

    In this case, the final checks confirmed:

    • The bug/patch number was recorded in AD_BUGS.
    • The corresponding applied-patch records were present.
    • AD and TXK were at the expected C.15 level.
    • EBS remained at Release 12.2.13.
    • Both application nodes were properly registered in FND_NODES.
    • Both nodes appeared correctly in ADOP_VALID_NODES.
    • adopscanlog reported no errors after the successful rerun.

    Together, these checks provide much stronger verification than relying on the final ADOP console message alone.

    Complete the Session with Cleanup

    After confirming the apply completed successfully, the session still showed:

    CLEANUP NOT STARTED

    The cleanup phase was then run:

    adop phase=cleanup

    After cleanup, perform another status and log review to make sure the session is in the expected final state.

    Key Takeaways

    Don’t rely only on ADOP’s exit status in a multi-node environment. In this incident, ADOP printed status = 0 (Success) even though the per-node summary clearly showed the slave node had failed.

    Check every application node before a downtime apply. A clean process list on the master does not guarantee the slave nodes are equally clean.

    Use the per-node ADOP status as part of your success criteriaadop -status -detail.

    Investigate the failed node before retrying. In this case a stale NodeManager process was discovered and removed before the successful retry. Unless supported by the logs, however, avoid treating correlation as a confirmed root cause.

    Resume the existing failed apply appropriately — after correcting the condition on the slave node, the existing apply was resumed from the master node with restart=yes.

    Use adopscanlog -latest=yes after the rerun.

    Verify patch registration in the databaseAD_BUGS, AD_APPLIED_PATCHES, AD_TRACKABLE_ENTITIES, FND_NODES, ADOP_VALID_NODES, FND_PRODUCT_GROUPS.

    Run ETCC and review its findings. If required database fixes are deferred, document and track them for the appropriate maintenance window rather than allowing them to become forgotten technical debt.

    Complete the ADOP cleanup phaseadop phase=cleanup.

    Final Thought

    Multi-node EBS patching adds a layer of validation that is easy to overlook: success on the master node does not automatically mean success across the application tier.

    The most useful lesson from this incident was not the retry command itself, but the validation process around it:

    Check every node → read the ADOP per-node summary → investigate the failed node → resume the existing session → scan the logs → verify the database records → complete cleanup.

    That sequence gives you a far more defensible and auditable patching result than relying on a single Success message at the end of the command.

    I hope this helps anyone troubleshooting a failed application-tier node during Oracle E-Business Suite R12.2 downtime patching. Feel free to leave a comment if you have questions.


    Disclaimer: The views expressed on this blog are my own and do not reflect the views of my employer or any client. All environment names, hostnames, and identifiers used in this post are anonymized. Always test in a non-production environment before applying any change to production.

  • Oracle EBS R12.2 AutoConfig Template Version Conflict After Patching: How to Preserve Customizations

    Alhamdulillah, sharing another real troubleshooting session — this one from an Oracle E-Business Suite R12.2 multi-node environment. After applying a patch, AutoConfig aborted on the primary application node with a template version conflict. This post walks through the exact error, how I identified which template entries were genuine customizations versus Oracle-shipped content, and the correct way to rebase a custom template so AutoConfig completes cleanly.

    Environment

    • Oracle E-Business Suite R12.2.13, AD/TXK Delta 15
    • Two application nodes: appsnode1 (primary/admin) and webnode1 (secondary web node)
    • Database: Oracle 19c on dbnode1
    • Third-party customization: More4Apps servlet registered in oacore web.xml

    The Error

    After patching, running AutoConfig on the run file system failed immediately:

    [applmgr@appsnode1 scripts]$ sh adautocfg.sh
    Enter the APPS user password:
    The log file for this session is located at: .../admin/log/<timestamp>/adconfig.log
    wlsDomainName: EBS_domain
    WLS Domain Name is VALID.
    AutoConfig is configuring the Applications environment...
    AutoConfig will consider the custom templates if present.
    Version Conflicts among development maintained and customized templates encountered; aborting AutoConfig run.

    The log pinpointed the conflicting template:

    [ FND_TOP ]
    
    [ VERSION CONFLICTS INFORMATION ]
    Template shipped by oracle is having a version different than the template lying in custom directory.
    Template shipped by Oracle : $FND_TOP/admin/template/oacore_web_xml_FMW.tmp (version: 120.17.12020000.33)
    Custom template            : $FND_TOP/admin/template/custom/oacore_web_xml_FMW.tmp (version: 120.17.12020000.31)
    Please resolve the differences between the two templates or refer to the Oracle E-Business Suite Setup Guide for further details.

    What happened is straightforward: the patch delivered a newer version of oacore_web_xml_FMW.tmp (120.17.12020000.33), but a custom copy of the older version (120.17.12020000.31) exists under $FND_TOP/admin/template/custom. AutoConfig detects the mismatch and refuses to run, because blindly using the stale custom template would silently discard whatever Oracle changed in the new version.

    Root Cause Analysis: What Is Actually a Customization?

    This is the critical analysis step. Before touching anything, you need to answer one question precisely: which lines in the custom template are genuine customizations, and which are just old Oracle-shipped content?

    First, take a backup and diff the new shipped template against the custom one:

    cd $FND_TOP/admin/template
    
    cp -p custom/oacore_web_xml_FMW.tmp \
          custom/oacore_web_xml_FMW.tmp.pre_patch_25Jul2026
    
    diff -u oacore_web_xml_FMW.tmp custom/oacore_web_xml_FMW.tmp

    The diff showed three differences beyond the header:

    1. A m4aServlet servlet and servlet-mapping (More4Apps) present only in the custom template
    2. A SyncServlet servlet and servlet-mapping present only in the custom template
    3. A RequestAuditReport (QP) servlet present only in the new Oracle template

    At first glance it looks like there are two customizations to carry forward: m4aServlet and SyncServlet. This is where a wrong assumption would corrupt the template. To verify, I compared the old shipped template against the new shipped template. In an R12.2 dual file system this is easy — the other file system still had the previous patch level, so both shipped versions were available:

    diff -u \
      <old_fs>/EBSapps/appl/fnd/12.0.0/admin/template/oacore_web_xml_FMW.tmp \
      <new_fs>/EBSapps/appl/fnd/12.0.0/admin/template/oacore_web_xml_FMW.tmp

    Key excerpt from the shipped-vs-shipped diff:

    -   <servlet>
    -     <servlet-name>SyncServlet</servlet-name>
    -     <servlet-class>oracle.apps.jtf.cac.sync.transport.SyncServlet</servlet-class>
    -  </servlet>
    ...
    +     <servlet>
    +         <servlet-name>RequestAuditReport</servlet-name>
    +         <servlet-class>oracle.apps.qp.servlet.RequestAuditReport</servlet-class>
    +    </servlet>

    This settled the question:

    • SyncServlet was Oracle-shipped content in version .31 and is no longer present in the .33 shipped template. It was never a customer customization, so it should NOT be carried forward.
    • RequestAuditReport is new Oracle-shipped content in .33 — it must be retained.
    • m4aServlet was not present in either shipped template version compared — it exists only in the custom directory, which identifies it as the genuine site-specific customization.

    If I had merged the old custom template on top of the new one, I would have reintroduced a servlet that is no longer present in Oracle’s newer shipped template. This is why “just copy your custom entries into the new template” advice found on many forums is dangerous — verify against the shipped versions first.

    The Fix: Rebase the Custom Template

    The correct approach: replace the custom template with the new shipped version, then re-apply only the genuine customization.

    cd $FND_TOP/admin/template
    
    # Rebase custom template on the new shipped version
    cp -p oacore_web_xml_FMW.tmp custom/oacore_web_xml_FMW.tmp
    
    # Re-insert the only genuine customization (m4aServlet)
    sed -i '/<!-- FND Servlets -->/a\
    \
      <servlet>\
        <servlet-name>m4aServlet</servlet-name>\
        <servlet-class>com.more4apps.r12.servlet.XmlServlet</servlet-class>\
      </servlet>\
    \
      <servlet-mapping>\
        <servlet-name>m4aServlet</servlet-name>\
        <url-pattern>/m4aServlet/*</url-pattern>\
      </servlet-mapping>\
    ' custom/oacore_web_xml_FMW.tmp

    This matches the procedure in the Oracle E-Business Suite Setup Guide: when a patch delivers a newer version of a template you have customized, copy the new Oracle template into the custom directory and reapply the still-required customizations to that copy — never the other way around.

    Verify before rerunning AutoConfig — the headers must match, and the only diff must be the customization:

    grep '\$Header' oacore_web_xml_FMW.tmp custom/oacore_web_xml_FMW.tmp
    
    oacore_web_xml_FMW.tmp:        version 120.17.12020000.33
    custom/oacore_web_xml_FMW.tmp: version 120.17.12020000.33
    
    diff -u oacore_web_xml_FMW.tmp custom/oacore_web_xml_FMW.tmp
    --- only the m4aServlet servlet + mapping block should appear ---

    As an additional best-practice validation, Oracle recommends running the AutoConfig configuration-check utility to preview the impact of template changes before the actual AutoConfig run:

    $AD_TOP/bin/adchkcfg.sh contextfile=$CONTEXT_FILE

    Rerun AutoConfig:

    cd $ADMIN_SCRIPTS_HOME
    sh adautocfg.sh
    
    ...
    Configuring templates from all of the product tops...
            Configuring AD_TOP........COMPLETED
            Configuring FND_TOP.......COMPLETED
            ...
    AutoConfig completed successfully.

    A Bonus Finding on the Second Node

    While repeating the check on the secondary web node, the header comparison came back clean — custom template already at .33 — but something was off:

    grep -n 'm4aServlet' $FND_TOP/admin/template/custom/oacore_web_xml_FMW.tmp
    (no output)
    
    grep -n 'm4aServlet' $FND_TOP/admin/template/custom/oacore_web_xml_FMW.tmp_ORIG
    61:    <servlet-name>m4aServlet</servlet-name>

    The current custom template matched the newer shipped version, but the m4aServlet customization was missing. Interestingly, the _ORIG backup still contained the customization. This indicated that during an earlier template update, the customization was not carried forward. AutoConfig had been running fine and web.xml was being generated — just without the third-party servlet.

    I re-inserted the m4aServlet block using the same sed command, verified the diff, and ran AutoConfig on that node as well:

    AutoConfig completed successfully.

    This is the real lesson of the post. A template version conflict at least fails loudly. A customization that is accidentally omitted during a template rebase may not — AutoConfig can complete successfully while the generated configuration no longer contains the required customization, and you find out later when the third-party tool stops working after a bounce.

    An Additional Message Observed

    The AutoConfig log in this run also contained:

    ECC not enabled, setting FND_ECC_ENABLED to FALSE
    [ FND_ECC_ENABLED ]
    INFO : Error updating/creating profile option value.

    In this case Enterprise Command Center is not configured, AutoConfig continued past this message, and the run ultimately exited with status 0. Always evaluate such messages in the context of your own environment rather than assuming every INFO : Error entry can be ignored.

    Post-Fix Checklist

    1. Confirm the customization landed in the generated web.xml (get the target path from the adconfig log and grep for your servlet).
    2. Bounce the application services (at least the oacore managed servers) so the new web.xml is deployed.
    3. Test the customization end to end — for More4Apps, hit the servlet URL from the wizard.
    4. If your patching cycle requires it, regenerate appsutil.zip (perl $AD_TOP/bin/admkappsutil.pl) and refresh the database tier.
    5. Repeat the custom template verification on every application node — as seen above, nodes can drift.

    Key Takeaways

    • Never resolve this error by copying the old custom template over the new shipped one, and never blindly merge either. The Oracle-documented procedure is to copy the new shipped template into the custom directory and re-apply only verified customizations to that copy.
    • Use the dual file system to your advantage: diff old-shipped vs new-shipped to separate Oracle’s changes from your customizations.
    • After any template rebase, diff the shipped and custom templates — the output should contain nothing but your customizations.
    • Audit custom templates on all nodes periodically. A missing customization may not trigger an AutoConfig error, allowing the generated configuration to differ from what you expect.

    I hope this helps someone facing the same conflict. Feel free to leave a comment if you have questions.


    Disclaimer: The views expressed on this blog are my own and do not reflect the views of my employer or any client. All environment names, hostnames, and identifiers used in this post are anonymized. Always test in a non-production environment before applying any change to production.

  • Applying Oracle 19c Apr 2026 CPU / RU 19.31 on a Single Instance CDB – Complete Patching Guide

    In this article, we are going to demonstrate the steps to apply the Oracle April 2026 Critical Patch Update (CPU) on a Single Instance Oracle 19c Container Database (CDB). Here we will apply combo patch 39062931 which contains 39034528 (Database Apr 2026 Release Update 19.31.0.0.260421) and 38906621 (OJVM Component Release Update 19.31.0.0.260421). We also cover an important real-world scenario where a previously applied overlay patch 34672698 (ORA-00800 fix) conflicted with the Apr 2026 RU — confirming that the fix is now natively included in the RU itself.

    Official References: This walkthrough is based on MOS Note CPU58Critical Patch Update (CPU) Apr 2026 for Oracle Database Products — and the Oracle April 2026 CPU Advisory (481 new security patches across all Oracle product families, released 21-Apr-2026).
    Patch Availability Note: The Linux x86-64 DB RU 39034528 was delayed post the standard Apr 21 release. Per MOS Note CPU58, the Linux x86-64 ETA was 15-May-2026. Always check CPU58 for the latest availability before scheduling your patching window.
    Downtime Notice: Applying a DB Release Update on a Single Instance (non-RAC) database requires a full database shutdown. Plan for a maintenance window accordingly and notify application teams in advance.
    Terminology Note: Oracle’s quarterly security bundle is commonly referred to as the Critical Patch Update (CPU). However, Oracle now delivers database fixes as Release Updates (RU). The term CPU refers to the overall security advisory, while RU is the actual patch artifact you apply. Both terms are used interchangeably in the field — this post uses CPU to align with the official advisory title.

    Environment Details

    Parameter Value
    Database Type Single Instance Oracle 19c CDB
    OS Oracle Linux x86-64
    Starting Version 19.30.0.0.0 (Jan 2026 RU)
    Target Version 19.31.0.0.0 (Apr 2026 RU)
    Combo Patch 39062931
    DB RU Patch 39034528
    OJVM RU Patch 38906621
    Overlay Patch (conflict) 34672698 (ORA-00800 fix — rolled back, natively included in 19.31)
    OPatch Version 12.2.0.1.51
    ORACLE_HOME /u03/app/oracle/product/19.0.0.0/db_1

    Section 1: Pre-Patch Checks

    1.1 Verify current database version

    sqlplus / as sysdba
    SQL> select version_full from v$instance;
    
    VERSION_FULL
    -----------------
    19.30.0.0.0

    1.2 Check existing SQL patch history (dba_registry_sqlpatch)

    SQL> set lines 200
    SQL> col description format a50
    SQL> col status format a10
    SQL> col action_time format a30
    SQL> select patch_id, action, status, action_time, description
      2  from dba_registry_sqlpatch
      3  order by action_time;
    PATCH_ID ACTION STATUS ACTION_TIME DESCRIPTION
    29517242 APPLY SUCCESS 2022-10-18 02:14:37 Database Release Update 19.17
    38632161 APPLY SUCCESS 2026-01-21 04:45:06 Database Release Update 19.30.0.0.260120
    38523609 APPLY SUCCESS 2026-01-21 04:49:43 OJVM Release Update 19.30.0.0.260120

    1.3 Check component registry (dba_registry)

    SQL> col comp_name format a45
    SQL> select comp_id, comp_name, version, status from dba_registry order by comp_id;
    COMP_ID COMP_NAME VERSION STATUS
    APS OLAP Analytic Workspace 19.0.0.0.0 VALID
    CATALOG Oracle Database Catalog Views 19.0.0.0.0 VALID
    CATJAVA Oracle Database Java Packages 19.0.0.0.0 VALID
    CATPROC Oracle Database Packages and Types 19.0.0.0.0 VALID
    CONTEXT Oracle Text 19.0.0.0.0 VALID
    DV Oracle Database Vault 19.0.0.0.0 VALID
    JAVAVM JServer JAVA Virtual Machine 19.0.0.0.0 VALID
    OLS Oracle Label Security 19.0.0.0.0 VALID
    ORDIM Oracle Multimedia 19.0.0.0.0 VALID
    OWM Oracle Workspace Manager 19.0.0.0.0 VALID
    SDO Spatial 19.0.0.0.0 VALID
    XDB Oracle XML Database 19.0.0.0.0 VALID
    XML Oracle XDK 19.0.0.0.0 VALID
    XOQ Oracle OLAP API 19.0.0.0.0 VALID

    1.4 Check invalid objects (baseline)

    SQL> select count(*) from dba_objects where status = 'INVALID';
    
      COUNT(*)
    ----------
             8
    Note: Record the baseline invalid object count. Any new invalids introduced by patching should be investigated. After datapatch, Oracle-supplied objects marked temporarily INVALID will recompile automatically. Only non-Oracle invalids or objects still INVALID after 24 hours need attention.

    1.5 Check current OPatch inventory

    $ORACLE_HOME/OPatch/opatch lspatches
    Patch ID Description
    34672698 ORA-00800 SOFT EXTERNAL ERROR, ARGUMENTS [SET PRIORITY FAILED], [VKTM], DISM(16)
    38523609 OJVM RELEASE UPDATE: 19.30.0.0.260120
    38632161 Database Release Update: 19.30.0.0.260120
    29585399 OCW RELEASE UPDATE 19.3.0.0.0
    Note on OCW patch 29585399: This OCW (Oracle Clusterware) patch appears in the OPatch inventory even on Single Instance (non-RAC) environments. This is expected behaviour — it is included in the base Oracle Home installation and is not a sign of misconfiguration.

    Section 2: Upgrade OPatch

    Before applying any patch, always upgrade OPatch to the latest version. Download the latest OPatch (p6880880) from MOS and apply.

    # As oracle user
    cd $ORACLE_HOME
    mv OPatch OPatch_backup_$(date +%Y%m%d)
    unzip /<patch_staging_dir>/p6880880_190000_Linux-x86-64.zip -d $ORACLE_HOME
    
    # Verify new version
    $ORACLE_HOME/OPatch/opatch version
    # Expected: OPatch Version: 12.2.0.1.51

    Section 3: Stage the Patches

    # Create staging directory
    mkdir -p /<patch_staging_dir>/APR_2026
    
    # Unzip combo patch (contains both DB RU and OJVM RU)
    cd /<patch_staging_dir>/APR_2026
    unzip p39062931_190000_Linux-x86-64.zip
    
    # Verify extraction
    ls -la
    # Should show: 38906621/  39034528/

    Section 4: Conflict Check

    # Check DB RU for conflicts
    cd /<patch_staging_dir>/APR_2026/39034528
    $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./
    
    # Check OJVM RU for conflicts
    cd /<patch_staging_dir>/APR_2026/38906621
    $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./
    Real-World Conflict Scenario (ZOP-47): In this environment, the conflict check returned a conflict between overlay patch 34672698 and the new DB RU 39034528. This is because the ORA-00800 fix originally delivered by 34672698 is now natively included in the 19.31 RU. The resolution is to roll back the overlay patch first before applying the RU. This is a standard ZOP-47 scenario — the overlay is superseded, not incompatible.

    Section 5: System Space Check

    # Check available space before patching
    $ORACLE_HOME/OPatch/opatch prereq CheckSystemSpace -ph /<patch_staging_dir>/APR_2026/39034528
    $ORACLE_HOME/OPatch/opatch prereq CheckSystemSpace -ph /<patch_staging_dir>/APR_2026/38906621
    
    # Also verify OS-level space
    df -h $ORACLE_HOME
    df -h /tmp

    Section 6: Take Oracle Home TAR Backup

    # As oracle user — use relative path approach to avoid absolute path issues
    cd $(dirname $ORACLE_HOME)
    nohup tar -czf /<backup_dir>/ORACLE_HOME_backup_$(date +%Y%m%d).tar.gz \
      $(basename $ORACLE_HOME) > /tmp/oh_tar_backup.log 2>&1 &
    
    echo "Backup PID: $!"
    tail -f /tmp/oh_tar_backup.log
    Note: Using $(dirname $ORACLE_HOME) and $(basename $ORACLE_HOME) avoids embedding absolute paths in the tar archive, making restoration cleaner. The nohup & pattern allows the backup to run in background without being killed if the session disconnects.

    Section 7: RMAN Backup (Verify)

    # Verify a recent RMAN backup exists before proceeding
    rman target /
    RMAN> list backup summary;
    RMAN> exit;
    Important: Never apply a patch without confirming a valid RMAN backup. If the latest backup is stale, take a fresh full backup before proceeding. The Oracle Home TAR covers binaries — RMAN covers your data.

    Section 8: Shutdown Database and Listener

    sqlplus / as sysdba
    SQL> shutdown immediate;
    SQL> exit;
    
    lsnrctl stop LISTENER

    Section 9: Roll Back Overlay Patch 34672698

    Because patch 34672698 conflicts with the Apr 2026 RU (its fix is now natively included), we must roll it back first.

    export PATH=$ORACLE_HOME/OPatch:$PATH
    cd $ORACLE_HOME/OPatch
    opatch rollback -id 34672698
    
    # Verify rollback
    opatch lspatches
    # 34672698 should no longer appear

    Section 10: Apply DB RU 39034528

    cd /<patch_staging_dir>/APR_2026/39034528
    
    # Apply (interactive)
    $ORACLE_HOME/OPatch/opatch apply
    
    # OR apply silently (for automation/scripts)
    $ORACLE_HOME/OPatch/opatch apply -silent
    Note on oradism permissions: In some environments the DB RU apply (opatch apply) itself automatically changes oradism ownership from root:oinstall to oracle:oinstall with permissions 755. Always check after applying the DB RU before attempting any manual root steps:

    ls -la $ORACLE_HOME/bin/oradism

    If oradism is already showing oracle:755 post-apply, the manual chown/chmod steps are not required. Only apply root permission changes if oradism remains root-owned after the patch apply.

    Section 11: Apply OJVM RU 38906621

    cd /<patch_staging_dir>/APR_2026/38906621
    $ORACLE_HOME/OPatch/opatch apply

    11.1 Verify OPatch inventory after apply

    $ORACLE_HOME/OPatch/opatch lspatches
    Patch ID Description
    38906621 OJVM RELEASE UPDATE: 19.31.0.0.260421
    39034528 Database Release Update: 19.31.0.0.260421
    29585399 OCW RELEASE UPDATE 19.3.0.0.0

    Note: Patch 34672698 no longer appears — successfully rolled back. Patch 34672698’s fix is now natively bundled into the 19.31 RU.

    Section 12: Start Database and Listener

    sqlplus / as sysdba
    SQL> startup;
    SQL> alter pluggable database all open;
    SQL> show pdbs;
    SQL> exit;
    
    lsnrctl start LISTENER
    lsnrctl status LISTENER

    Section 13: Run Datapatch

    Datapatch applies the SQL-level changes for the new patches into the CDB and all open PDBs. This step is mandatory — OPatch alone does not apply SQL changes.

    cd $ORACLE_HOME/OPatch
    
    # Run datapatch and capture output to log
    ./datapatch -verbose | tee /tmp/datapatch_19_31.log
    Note on tee and exit codes: Using tee in a pipeline means the shell reports the exit code of tee, not datapatch. If you need to capture datapatch’s actual exit code for scripted validation, use: ./datapatch -verbose > /tmp/datapatch_19_31.log 2>&1; echo "Exit code: $?"

    Section 14: Post-Patch Validation

    14.1 Verify dba_registry_sqlpatch (post-patch)

    SQL> select patch_id, action, status, action_time, description
      2  from dba_registry_sqlpatch
      3  order by action_time;
    PATCH_ID ACTION STATUS ACTION_TIME DESCRIPTION
    34672698 ROLLBACK SUCCESS 17-MAY-26 09.12.43 AM ORA-00800 fix (overlay)
    38523609 ROLLBACK SUCCESS 17-MAY-26 09.15.02 AM OJVM Release Update 19.30
    39034528 APPLY SUCCESS 17-MAY-26 09.21.18 AM Database Release Update 19.31.0.0.260421
    38906621 APPLY SUCCESS 17-MAY-26 09.25.47 AM OJVM Release Update 19.31.0.0.260421

    14.2 Verify dba_registry (post-patch)

    SQL> select comp_id, comp_name, version, status from dba_registry order by comp_id;
    COMP_ID COMP_NAME VERSION STATUS
    APS OLAP Analytic Workspace 19.0.0.0.0 VALID
    CATALOG Oracle Database Catalog Views 19.0.0.0.0 VALID
    CATJAVA Oracle Database Java Packages 19.0.0.0.0 VALID
    CATPROC Oracle Database Packages and Types 19.0.0.0.0 VALID
    CONTEXT Oracle Text 19.0.0.0.0 VALID
    DV Oracle Database Vault 19.0.0.0.0 VALID
    JAVAVM JServer JAVA Virtual Machine 19.0.0.0.0 VALID
    OLS Oracle Label Security 19.0.0.0.0 VALID
    ORDIM Oracle Multimedia 19.0.0.0.0 VALID
    OWM Oracle Workspace Manager 19.0.0.0.0 VALID
    SDO Spatial 19.0.0.0.0 VALID
    XDB Oracle XML Database 19.0.0.0.0 VALID
    XML Oracle XDK 19.0.0.0.0 VALID
    XOQ Oracle OLAP API 19.0.0.0.0 VALID

    14.3 Verify version

    SQL> select version_full from v$instance;
    
    VERSION_FULL
    -----------------
    19.31.0.0.0

    14.4 Check invalid objects (post-patch)

    SQL> select count(*) from dba_objects where status = 'INVALID';
    
      COUNT(*)
    ----------
             8

    Invalid count unchanged from baseline — no new invalids introduced by patching.

    14.5 Run utlrp.sql (conditional)

    Note: Running utlrp.sql is conditional — only required if you see new invalid objects that were not in the baseline count, or if Oracle-supplied objects remain INVALID after 24 hours. It is not mandatory after every patch apply.
    -- Only run if new invalids are found
    sqlplus / as sysdba
    SQL> @?/rdbms/admin/utlrp.sql

    14.6 CDB-aware validation (cdb_registry_sqlpatch)

    -- Run from CDB$ROOT to validate across all containers
    SQL> col con_id format 99
    SQL> col patch_id format 9999999999
    SQL> col status format a10
    SQL> col action format a10
    SQL> select con_id, patch_id, action, status, description
      2  from cdb_registry_sqlpatch
      3  order by con_id, action_time;
    Note: cdb_registry_sqlpatch shows the patch apply status for each container (CDB$ROOT and all PDBs). Use this view to confirm datapatch applied successfully in all PDBs, not just the root container. All rows should show SUCCESS.

    Section 15: Rollback Procedure (If Required)

    If the patch causes critical issues post-apply, roll back in reverse order: OJVM first, then DB RU. This requires full database downtime.

    15.1 Shutdown the database and listener

    sqlplus / as sysdba
    SQL> shutdown immediate;
    SQL> exit;
    
    lsnrctl stop LISTENER

    15.2 Roll back the OJVM patch first

    export PATH=$ORACLE_HOME/OPatch:$PATH
    opatch rollback -id 38906621
    
    OPatch succeeded.

    15.3 Roll back the DB RU

    opatch rollback -id 39034528
    
    OPatch succeeded.

    15.4 Verify Jan 2026 RU is restored

    opatch lspatches
    -- Expect to see 38632161 and 38523609 back as active

    15.5 Start database, open PDBs, run datapatch

    sqlplus / as sysdba
    SQL> startup;
    SQL> alter pluggable database all open;
    SQL> show pdbs;
    SQL> exit;
    
    cd $ORACLE_HOME/OPatch
    ./datapatch -verbose
    Important: If the Oracle Home is severely corrupted, restore from the Oracle Home TAR backup taken in Section 6, then run datapatch. If database files are also affected, restore and recover from the RMAN backup first, then run datapatch. Never skip datapatch after a rollback — the SQL layer must be consistent with the binary layer.

    Section 16: Common Failures and Troubleshooting

    ZOP-47: Conflict with existing overlay patch

    Symptom: opatch prereq CheckConflictAgainstOHWithDetail reports a conflict between an installed overlay patch and the new RU.

    Cause: The overlay patch fix has been natively absorbed into the new RU.

    Resolution: Roll back the overlay patch using opatch rollback -id <patch_id>, then proceed with the RU apply. Confirm with Oracle Support SR if unsure whether the conflict is a ZOP-47 (self-resolving) or a genuine incompatibility.

    ZOP-40: Patch already installed

    Symptom: OPatch reports the patch is already present in the inventory.

    Cause: Patch was applied in a previous cycle or the inventory is stale.

    Resolution: Verify with opatch lspatches. If genuinely already installed, no action needed. If inventory is stale, run opatch lsinventory -detail to diagnose.

    Datapatch skipped PDB

    Symptom: Datapatch log shows one or more PDBs were skipped.

    Cause: PDB was not open during datapatch execution.

    Resolution: Open the skipped PDB (alter pluggable database <pdb_name> open;) and re-run datapatch. Confirm via cdb_registry_sqlpatch that all containers show SUCCESS.

    OPatch heap space error

    Symptom: OPatch fails with a Java heap space error during apply.

    Cause: Default JVM heap is insufficient for large patch sets.

    Resolution: Set JAVA_TOOL_OPTIONS="-Xmx512m" before running opatch. This is environment-specific and not universally required — only apply if the error is observed.

    OPatch inventory lock

    Symptom: OPatch fails reporting the inventory is locked by another process.

    Cause: A previous OPatch run did not exit cleanly, leaving a lock file.

    Resolution: Check for and remove the lock file: $ORACLE_HOME/.patch_storage/<lock_file>. Confirm no other OPatch process is running before removing.

    Key MOS References

    Document Description
    Doc ID CPU58 Critical Patch Update (CPU) Apr 2026 for Oracle Database Products — patch availability, known issues, delayed RU tracking
    Doc ID KB106822 Primary Note for Database Quarterly Release Updates — recommended reading before any RU apply
    Doc ID KB869205 Oracle Database 19c Apr 2026 RU Known Issues
    Doc ID KB137197 OJVM Conditional Rolling Install Details
    Doc ID 244241.1 OPatch Support for RAC Rolling Patches
    Doc ID 293369.1 OPatch Documentation List

    Disclaimer: All server names, hostnames, database names, and environment-specific paths in this post have been anonymized. Steps and outputs are based on real production experience adapted for general use. Always test in a non-production environment before applying patches to production systems.

    If you found this useful, connect with me on LinkedIn or explore more Oracle DBA scripts on my GitHub. More patching walkthroughs at syedanwarahmedoracle.blog.

    Share Your Experience

    Have you applied Oracle 19c CPU patches and hit a similar overlay patch conflict? Or found that a fix you applied months ago is now natively bundled into the next RU? Your real-world experiences help fellow DBAs tackle the same challenges. Drop a comment below — questions, observations, and feedback are always welcome.

  • Oracle EBS 12.2 — ADOP fs_clone Failure: Failed to Delete FMW_Home (Root Cause & Fix)

    Category: Oracle EBS 12.2  |  Topic: ADOP Patching  |  Difficulty: Intermediate  |  Oracle Support: Search ADOP fs_clone Failed to delete FMW_Home on My Oracle Support

    Introduction

    Oracle EBS 12.2 introduced Online Patching (ADOP), which relies on a dual file system architecture — a Run File System (fs2) where production runs, and a Patch File System (fs1) where patches are applied. The fs_clone phase synchronises fs1 from fs2 at the start of each patching cycle, making fs1 a fresh copy of the production file system.

    One of the most common issues encountered during fs_clone is a failure while trying to delete the FMW_Home directory on the Patch FS. This blog walks through a real production scenario on a 2-node RAC database with 4 application server nodes — covering the exact error, step-by-step diagnostic process, root cause identification, fix applied, and the final successful run with actual timings. All server-specific details have been anonymised.

    This issue applies to Oracle EBS 12.2.x on all platforms. For related Oracle Support articles, search “ADOP fs_clone Failed to delete FMW_Home” on My Oracle Support.

    Environment

    ParameterValue
    ApplicationOracle E-Business Suite 12.2 (2-Node RAC DB + 4 Application Server Nodes)
    ADOP VersionC.Delta.13
    ADOP Session ID129
    Run File System (fs2)/u01/app/fs2 (Production — active)
    Patch File System (fs1)/u01/app/fs1 (Inactive — patching target)
    Shared StorageNFS-mounted shared volume (1.3T, 447G free)
    OS Userapplmgr

    Incident Timeline

    EventTimestampDurationOutcome
    1st run startedApr 11, 2026 17:07:35time adop phase=fs_clone executed
    1st run failedApr 11, 2026 ~18:41~1h 34mFATAL ERROR — FMW_Home deletion failed
    Diagnosis performedApr 11, 2026 18:45–19:44~59mRoot cause identified — root-owned OHS log files
    Fix applied (mv)Apr 11, 2026 ~19:44SecondsFMW_Home renamed to dated backup as applmgr
    2nd run startedApr 11, 2026 19:45time adop phase=fs_clone re-executed after fix
    2nd run completedApr 12, 2026 00:49:085h 21m 25sSUCCESS — all 4 app nodes completed ✅
    Total session elapsedApr 11 17:07 → Apr 12 00:497h 46m 33sFull session including failed run + fix + retry

    The Issue

    During time adop phase=fs_clone, the synchronisation process was progressing normally — staging the file system clone, detaching Oracle Homes, removing APPL_TOP and COMM_TOP — until it reached stage 6 (REMOVE-1012-ORACLE-HOME) inside the removeFMWHome() function, where it attempted to delete the FMW_Home directory on the Patch FS and hit a fatal error.

    Error on the Console

    fs_clone/remote_execution_result_level1.xml:
    *******FATAL ERROR*******
    PROGRAM : (.../fs2/EBSapps/appl/ad/12.0.0/patch/115/bin/txkADOPPreparePhaseSynchronize.pl)
    TIME    : Apr 11 18:41:40 2026
    FUNCTION: main::removeDirectory [ Level 1 ]
    ERRORMSG: Failed to delete the directory /u01/app/fs1/FMW_Home.
    [UNEXPECTED]fs_clone has failed

    Key Log File: txkADOPPreparePhaseSynchronize.log

    The primary log file is located at:

    $ADOP_LOG_DIR/<session_id>/<timestamp>/fs_clone/<node>/TXK_SYNC_create/
        txkADOPPreparePhaseSynchronize.log

    Inside this log, the clone status progression was clearly visible:

    ========================== Inside getCloneStatus()... ==========================
    clone_status             = REMOVE-1012-ORACLE-HOME
    clone_status_from_caller = 7
    clone_status_from_db     = 6
    Removing the directory: /u01/app/fs1/FMW_Home
    Failed to delete the directory /u01/app/fs1/FMW_Home.
    *******FATAL ERROR*******
    FUNCTION: main::removeDirectory [ Level 1 ]
    ERRORMSG: Failed to delete the directory /u01/app/fs1/FMW_Home.

    clone_status_from_db = 6 indicates the process had already completed: fs_clone staging, detach of Oracle Homes, removal of APPL_TOP, COMM_TOP, and 10.1.2 Oracle Home. It failed specifically and only while removing FMW_Home.

    ADOP fs_clone Stage Flow

    Stage DBClone StatusDescription
    1STARTEDSession initialised
    2FSCLONESTAGE-DONEFile system staging completed
    3DEREGISTER-ORACLE-HOMESOracle Homes deregistered from inventory
    4REMOVE-APPL-TOPAPPL_TOP removed from Patch FS
    5REMOVE-COMM-TOPCOMM_TOP removed from Patch FS
    6REMOVE-1012-ORACLE-HOMERemoving FMW_Home — ❌ FAILED HERE
    7+(clone proceeds…)Clone fs2 to fs1, re-register homes, config clone

    Diagnostic Steps

    Step 1 — Confirm You Are on the Correct File System

    Most critical check first. The target must be on Patch FS (fs1), never Run FS (fs2):

    echo $FILE_EDITION   # Must show: run
    echo $RUN_BASE       # Must show path to fs2
    $ echo $FILE_EDITION
    run
    $ echo $RUN_BASE
    /u01/app/fs2

    ⚠️ If FILE_EDITION shows patch, stop immediately — source the Run FS environment before proceeding.

    Step 2 — Check for Open File Handles

    lsof +D /u01/app/fs1/FMW_Home 2>/dev/null
    fuser -cu /u01/app/fs1/FMW_Home 2>&1

    In our case both commands returned empty output — no active process was holding FMW_Home open.

    Step 3 — Identify Root-Owned Files

    find /u01/app/fs1/FMW_Home ! -user applmgr -ls 2>/dev/null

    Output revealed multiple root-owned files under the OHS instance directories:

    drwxr-x---  3 root root 4096 Feb 15 06:48 .../EBS_web_OHS4/auditlogs/OHS
    -rw-------  1 root root    0 Feb 15 06:48 .../EBS_web_OHS4/diagnostics/logs/OHS/EBS_web/sec_audit_log
    -rw-r-----  1 root root 5670 Feb 15 06:49 .../EBS_web_OHS4/diagnostics/logs/OHS/EBS_web/EBS_web.log
    -rw-r-----  1 root root  249 Feb 15 06:49 .../EBS_web_OHS4/diagnostics/logs/OHS/EBS_web/access_log
    ... (same pattern for EBS_web_OHS2 and EBS_web_OHS3)

    All root-owned files were dated February 15 — nearly 2 months stale. This confirmed they were leftovers from OHS being incorrectly started as root during a previous patching cycle. No active process was involved.

    Step 4 — Attempt Manual Delete to Confirm the Error

    rm -rf /u01/app/fs1/FMW_Home 2>&1 | head -5
    rm: cannot remove '.../EBS_web_OHS4/diagnostics/logs/OHS/EBS_web/sec_audit_log': Permission denied

    This confirmed the issue was purely a file ownership/permission problem — not filesystem corruption or an NFS issue.

    Step 5 — Check Disk Space

    df -h /u01/app/fs1
    Filesystem      Size  Used Avail Use% Mounted on
    nfs_server:/vol  1.3T  844G  447G  66% /u01

    447GB free — sufficient to retain a backup of FMW_Home by renaming it.

    Root Cause Analysis

    The root cause was OHS (Oracle HTTP Server) being started as root on the Patch File System during a previous patching cycle in February 2026. This created log and audit files owned by root under:

    /u01/app/fs1/FMW_Home/webtier/instances/EBS_web_OHS2/auditlogs/OHS/
    /u01/app/fs1/FMW_Home/webtier/instances/EBS_web_OHS2/diagnostics/logs/OHS/EBS_web/
    /u01/app/fs1/FMW_Home/webtier/instances/EBS_web_OHS3/  (same structure)
    /u01/app/fs1/FMW_Home/webtier/instances/EBS_web_OHS4/  (same structure)

    Since fs_clone runs as applmgr, and applmgr cannot delete files owned by root, the removeDirectory() function in txkADOPPreparePhaseSynchronize.pl failed with Permission Denied — surfaced as a fatal error.

    Why did OHS create root-owned files? If OHS start/stop scripts are executed as root or with sudo (instead of using applmgr-owned wrapper scripts), the resulting log and audit files are created with root ownership and persist on the Patch FS across patching cycles.

    Pre-Action Safety Checklist

    CheckExpectedResult
    FILE_EDITION = runrun✅ PASS
    RUN_BASE points to fs2/u01/app/fs2✅ PASS
    FMW_Home target is on fs1 (Patch FS only)fs1 only✅ PASS
    lsof returns empty (no open handles)Empty✅ PASS
    Root-owned files are stale (no active processes)Stale only✅ PASS
    Sufficient disk space for backup rename> 50GB free✅ PASS
    Production services confirmed running on fs2fs2 up✅ PASS

    Solution — Move FMW_Home as Backup

    The safest approach on production is to move (rename) FMW_Home rather than deleting it. This avoids the need for root access entirely, completes in seconds, and preserves a backup.

    Why mv works even with root-owned files: mv on the same filesystem is a purely atomic rename at the directory level. It does not touch or modify any file contents inside the directory — so applmgr can rename FMW_Home even if files inside are owned by root. This is fundamentally different from rm -rf, which must access and remove each individual file.

    Step 1 — Move FMW_Home as a Dated Backup

    mv /u01/app/fs1/FMW_Home /u01/app/fs1/FMW_Home_$(date +%d%b%Y)_bkp && echo "MOVE SUCCESSFUL"
    MOVE SUCCESSFUL

    Step 2 — Verify FMW_Home Is Gone

    ls -lrt /u01/app/fs1/

    Step 3 — Confirm You Are applmgr Before Retrying

    whoami
    # Expected output: applmgr

    ⚠️ Never run adop as root. Always confirm whoami shows applmgr before executing any adop command.

    Step 4 — Retry fs_clone

    time adop phase=fs_clone

    Running fs_clone Safely on Production

    time adop phase=fs_clone on a 2-node RAC with 4 application server nodes takes several hours. Never run it in a plain SSH/PuTTY session that could disconnect. Use one of the following:

    • VNC Session (Best): Network drops have zero impact on the running process.
    • nohup: nohup adop phase=fs_clone > /tmp/fsclone_$(date +%Y%m%d_%H%M%S).log 2>&1 &
    • screen: screen -S fsclone then time adop phase=fs_clone. Detach with Ctrl+A D, reattach with screen -r fsclone.

    Successful Run — 2nd Attempt

    After applying the fix, time adop phase=fs_clone was re-executed. The adopmon output confirmed all 4 application nodes progressing through validation, port blocking, clone steps, and config clone phases without any errors.

    ADOP (C.Delta.13)
    Session Id: 129
    Command:    status
    Node Name   Node Type  Phase        Status     Started               Finished              Elapsed
    ----------  ---------  -----------  ---------  --------------------  --------------------  -------
    app-node1   master     FS_CLONE     COMPLETED  2026/04/11 17:07:35   2026/04/12 00:49:08   7:46:33
    app-node2   slave      CONFIG_CLONE COMPLETED  2026/04/11 17:07:36   2026/04/12 01:01:55   7:47:19
    app-node3   slave      CONFIG_CLONE COMPLETED  2026/04/11 17:07:36   2026/04/12 01:01:25   7:47:49
    app-node4   slave      CONFIG_CLONE COMPLETED  2026/04/11 17:07:36   2026/04/12 01:02:16   7:47:40
    File System Synchronization Type: Full
    adop exiting with status = 0 (Success)
    Summary report for current adop session:
        Node app-node1:  - Fs_clone status: Completed successfully
        Node app-node2:  - Fs_clone status: Completed successfully
        Node app-node3:  - Fs_clone status: Completed successfully
        Node app-node4:  - Fs_clone status: Completed successfully
    adop exiting with status = 0 (Success)
    real    321m25.733s   (5 hours 21 minutes 25 seconds)
    user     40m1.142s
    sys      70m59.804s
    NodeTypeStartedFinishedElapsed
    app-node1MasterApr 11, 2026 17:07:35Apr 12, 2026 00:49:087h 46m 33s
    app-node2SlaveApr 11, 2026 17:07:36Apr 12, 2026 01:01:557h 47m 19s
    app-node3SlaveApr 11, 2026 17:07:36Apr 12, 2026 01:01:257h 47m 49s
    app-node4SlaveApr 11, 2026 17:07:36Apr 12, 2026 01:02:167h 47m 40s

    The 2nd run completed cleanly in 5 hours 21 minutes 25 seconds across all 4 application nodes. File System Synchronization Type: Full.

    Post-Resolution Cleanup

    After a successful fs_clone and full patching cycle, old FMW_Home backups can be removed. Keep the most recent backup until the next patching cycle completes, then clean up older ones as root (since they may contain root-owned files):

    ls -lrt /u01/app/fs1/FMW_Home*
    du -sh /u01/app/fs1/FMW_Home*
    # Remove old backups as root
    sudo rm -rf /u01/app/fs1/FMW_Home_<old_date>_bkp

    Prevention — Avoiding Recurrence

    • Never start OHS as root. Always use applmgr-owned wrapper scripts. Never use sudo or root to run adohs.sh or adadminsrvctl.sh.
    • Post-patching ownership check. After every adop finalize/cutover, run: find /u01/app/fs1 ! -user applmgr -ls 2>/dev/null | head -20
    • Pre-fs_clone health check. Verify no lingering adop sessions, confirm Run FS services are healthy, check disk space, and verify no root-owned files under fs1/FMW_Home before starting.

    Summary

    ItemDetail
    Phaseadop phase=fs_clone
    Failing Functionmain::removeDirectory inside removeFMWHome()
    Clone Stageclone_status_from_db = 6 (REMOVE-1012-ORACLE-HOME)
    Root CauseOHS started as root in a previous cycle — stale root-owned OHS log/audit files blocking applmgr deletion
    Production ImpactNone — fs1 is Patch FS, production ran on fs2 throughout
    Fix Appliedmv FMW_Home to dated backup as applmgr — atomic rename, no root needed, completed in seconds. rm -rf was NOT used.
    1st Run Duration~1h 34m before fatal error (Apr 11 17:07 → 18:41)
    2nd Run Duration5h 21m 25s — completed successfully (Apr 11 19:45 → Apr 12 00:49)
    Total Session Elapsed7h 46m 33s (including failed run, diagnosis, fix, and retry)
    Final Statusadop exiting with status = 0 (Success) — all 4 app nodes completed ✅
    PreventionNever start OHS as root; add post-patching ownership check to runbook
    Oracle SupportSearch “ADOP fs_clone Failed to delete FMW_Home” on My Oracle Support

    Happy Debugging! All server-specific details have been anonymised. The diagnostic commands and fix are generic and applicable to any Oracle EBS 12.2.x environment. If this helped you, feel free to share with the community.

  • When ADOP Remembers Too Much: Fixing Patch Failures Caused by Stale Metadata in Oracle EBS

    During an Oracle E-Business Suite ADOP patching cycle in a multi-node environment, the apply phase failed on one node while completing successfully on others. Despite retries — including downtime mode — the issue persisted, pointing to a deeper inconsistency within the patching framework.


    Symptoms Observed

    • ADOP session status: FAILED
    • Patch applied successfully on some nodes, failed on admin node
    • Repeated failures even with restart=no, abandon=yes, and downtime mode
    • No immediate actionable error from standard logs

    Timeline of Events

    T0 -- Patch execution initiated (ADOP apply phase)
    T1 -- Failure observed on admin node
    T2 -- Retry using downtime mode -- Failure persists
    T3 -- ADOP session review shows inconsistent state
    T4 -- Internal metadata tables analyzed
    T5 -- Cleanup performed (tables + restart directory)
    T6 -- Patch re-executed -- Success across all nodes

    Investigation

    Step 1: Check ADOP Session State

    Query the ADOP session status to understand the current state across all nodes:

    -- Check current ADOP session status
    SELECT session_id, node_name, phase, status,
           start_date, end_date
    FROM applsys.ad_adop_sessions
    ORDER BY start_date DESC;
    
    -- Check apply phase status per node
    SELECT s.session_id, n.node_name, p.phase_code,
           p.status, p.start_date, p.end_date
    FROM applsys.ad_adop_sessions s,
         applsys.ad_adop_session_phases p,
         applsys.fnd_nodes n
    WHERE s.session_id = p.session_id
    AND p.node_id = n.node_id
    ORDER BY p.start_date DESC;

    The existing session showed status FAILED with the apply phase partially completed — a clear indicator of inconsistent execution state across nodes.

    Step 2: Check adalldefaults.txt

    Reviewed the defaults file for any relevant configuration:

    cat $APPL_TOP/admin/$TWO_TASK/adalldefaults.txt | grep -i missing
    -- Key parameter found:
    -- MISSING_TRANSLATED_VERSION = No

    Modifying and retrying with this parameter had no impact, confirming the issue was not translation-related.

    Step 3: Check Install Processes Table

    -- Check for stale entries in FND_INSTALL_PROCESSES
    SELECT COUNT(*) FROM applsys.fnd_install_processes;
    
    -- View stale entries in detail
    SELECT process_status, process_name, last_update_date
    FROM applsys.fnd_install_processes
    ORDER BY last_update_date DESC;
    
    -- Check AD_DEFERRED_JOBS
    SELECT COUNT(*) FROM applsys.ad_deferred_jobs;
    SELECT * FROM applsys.ad_deferred_jobs;

    Observation: FND_INSTALL_PROCESSES contained stale entries from the failed session. AD_DEFERRED_JOBS was empty.


    Root Cause

    The failure was caused by stale and inconsistent ADOP metadata tables — specifically APPLSYS.FND_INSTALL_PROCESSES and APPLSYS.AD_DEFERRED_JOBS. ADOP internally relies on these tables to track patch progress checkpoints, deferred job execution, and restart state management. When these tables retain entries from failed or incomplete sessions, ADOP assumes an incorrect execution state, leading to patch reconciliation failure, apply phase breakdown, and node-level inconsistencies.


    Resolution Steps

    Step 1: Backup Critical Tables

    -- Always backup before any cleanup
    CREATE TABLE applsys.fnd_install_processes_bak AS
    SELECT * FROM applsys.fnd_install_processes;
    
    CREATE TABLE applsys.ad_deferred_jobs_bak AS
    SELECT * FROM applsys.ad_deferred_jobs;
    
    -- Verify backups
    SELECT COUNT(*) FROM applsys.fnd_install_processes_bak;
    SELECT COUNT(*) FROM applsys.ad_deferred_jobs_bak;

    Step 2: Drop Stale Metadata Tables

    Dropping these tables forces ADOP to rebuild clean metadata during the next run:

    DROP TABLE applsys.fnd_install_processes;
    DROP TABLE applsys.ad_deferred_jobs;

    Step 3: Reset the Restart Directory

    The restart directory can silently preserve failure states. Back it up and create a fresh one:

    cd $APPL_TOP/admin/$TWO_TASK
    
    -- Backup existing restart directory
    mv restart restart_bkp_$(date +%Y%m%d)
    
    -- Create fresh restart directory
    mkdir restart
    
    -- Verify
    ls -la | grep restart

    Step 4: Re-run the Patch

    adop phase=apply \
         patches=<patch_id> \
         restart=no \
         abandon=yes \
         apply_mode=downtime

    The patch completed successfully across all nodes after the metadata cleanup.


    Before vs After

    ComponentBefore FixAfter Fix
    ADOP SessionFailedSuccessful
    Node ConsistencyPartialFull
    Restart BehaviorStuckClean
    Patch ExecutionIncompleteCompleted

    Key Takeaways

    • ADOP is state-driven — even when logs appear clean, internal metadata drives execution decisions
    • Partial success is a clue — if some nodes succeed and one fails, focus on local metadata, not the patch itself
    • The restart directory matters — it can silently preserve failure states and must be validated before retrying
    • Downtime mode is not a fix-all — even in downtime, ADOP still reads metadata tables; corruption persists unless cleaned
    • Always backup before cleanup — never drop tables without creating a backup first

    When NOT to Use This Approach

    Avoid applying this fix if the issue is caused by missing database patches (ETCC warnings), file system or permission issues, incorrect patch sequencing, or environment misconfiguration. Always validate the root cause before performing any metadata cleanup.


    This scenario highlights a subtle but critical behavior in ADOP — sometimes patch failures are not caused by the patch itself, but by what the system remembers about past attempts. By resetting stale metadata, we allow ADOP to re-evaluate the environment cleanly, leading to successful execution.

    Have questions or faced a similar issue? Reach out at sdanwarahmed@gmail.com.