Blog

  • Resolving 98% Filesystem Usage with RMAN DELETE OBSOLETE: A Production DBA Case Study

    On a Saturday afternoon, a production database host reported its backup filesystem at 98% used. This post walks through how I handled it with RMAN, what the output showed, and which parts were still open when I stopped capturing evidence.

    The symptom

    The backup filesystem (/backup_fs, about 9.9T) was nearly full. The first check showed 282G free, and a later check showed 221G:

    $ df -h /backup_fs
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/sdX1       9.9T  9.2T  221G  98% /backup_fs

    An incremental backup was also running to the same location, so the filesystem was still being written to. A full filesystem would have failed that job, which is why this was urgent.

    Initial checks

    I started with three things:

    1. df -h to confirm the numbers.
    2. date; hostname to confirm I was on the right server and to timestamp my notes.
    3. The status of the running backup job.
    SET LINESIZE 120
    SET PAGESIZE 50
    
    COLUMN STATUS               FORMAT A12
    COLUMN OUTPUT_BYTES_DISPLAY FORMAT A15
    COLUMN TIME_TAKEN_DISPLAY   FORMAT A15
    
    -- Replace <session_key> with the relevant RMAN session key
    SELECT SESSION_KEY,
           STATUS,
           OUTPUT_BYTES_DISPLAY,
           TIME_TAKEN_DISPLAY
    FROM   V$RMAN_BACKUP_JOB_DETAILS
    WHERE  SESSION_KEY = <session_key>;

    The job was RUNNING, so whatever I did next had to leave it alone.

    Obsolete vs. expired

    These two get mixed up often.

    • Obsolete is decided by the retention policy. Here it was RECOVERY WINDOW OF 5 DAYS. A backup is obsolete when RMAN determines it is no longer needed to satisfy that policy. That does not mean every backup older than five days is obsolete, because RMAN checks whether the recovery window can still be met without it.
    • Expired is a repository status set by CROSSCHECK when RMAN cannot find a piece on disk.

    I ran LIST EXPIRED BACKUP; first. It returned “specification does not match any backup in the repository.” At that point, RMAN had no backup pieces marked EXPIRED in its repository. That did not mean no obsolete backups existed, and REPORT OBSOLETE showed that they did.

    Reviewing what RMAN considered obsolete

    RMAN> REPORT OBSOLETE;
    
    RMAN retention policy will be applied to the command
    RMAN retention policy is set to recovery window of 5 days

    The report listed backup pieces completed on 03, 12, 13 and 17 October, all in the backup directory, including several control file autobackup pieces.

    REPORT OBSOLETE only reports. It applies the configured policy and changes nothing. I reviewed the list before going further.

    Approval and DELETE OBSOLETE

    This is a production backup area, so I got Tier 3 approval before deleting anything. Once that was confirmed:

    RMAN> DELETE OBSOLETE;

    RMAN allocated six disk channels, listed the objects, and asked for confirmation:

    Do you really want to delete the above objects (enter YES or NO)? YES

    After I confirmed, RMAN printed deleted backup piece messages along with Deleted 5 objects and Deleted 6 objects summaries.

    I did not remove any files from the shell with rm. Deleting RMAN files at the OS level leaves the repository believing they still exist. A CROSSCHECK can reconcile that later, but it adds cleanup work and risk you do not need on a production system.

    The RMAN-06207 / RMAN-06208 warnings

    Mixed in with the successful deletions, RMAN repeatedly printed:

    RMAN-06207: warning: 4 objects could not be deleted for DISK channel(s) due
    RMAN-06208:          to mismatched status.  Use CROSSCHECK command to fix status
    RMAN-06210: List of Mismatched objects
    ...
    RMAN-06214: Backup Piece    <backup_piece_handle>

    Each warning listed four backup pieces, and there were six such groups. Two observations from the log:

    • Every handle in the mismatch lists belonged to the 03-Oct group of obsolete backups.
    • RMAN’s message says what it expects: the repository status did not match what the channel found, and CROSSCHECK is the way to correct it.

    That is an observation from the captured log, not a root-cause conclusion. I am not guessing why those pieces mismatched, because the log does not say.

    CROSSCHECK BACKUP

    RMAN> CROSSCHECK BACKUP;

    CROSSCHECK BACKUP checks whether backup pieces recorded in the RMAN repository are accessible on their associated storage. Depending on the result, RMAN updates their status to AVAILABLE or EXPIRED. It does not delete backup pieces.

    The output I captured showed pieces reported like this:

    backup piece handle=<backup_piece_handle> RECID=<n> STAMP=<n>
    crosschecked backup piece: found to be 'AVAILABLE'

    Be careful about what this does and does not prove. It confirmed that the pieces in my captured excerpt were AVAILABLE. It did not show that every handle from the RMAN-06207 lists had been crosschecked, and the excerpt displayed different handles from the warnings. So I cannot say the mismatched pieces were resolved.

    Before and after

    All values are rounded df -h output, so I am not claiming exact bytes reclaimed.

    CheckSizeUsedAvailUse%
    Initial9.9T9.2T282G98%
    Pre-cleanup9.9T9.2T221G98%
    After cleanup9.9T6.0T3.5T64%
    Later9.9T6.1T3.5T64%
    Latest9.9T6.1T3.4T65%

    Following the cleanup, reported free space increased from approximately 221G to 3.4–3.5T, while utilization dropped from 98% to 64–65%. These are observed filesystem measurements; I have not attributed every byte of the change to a specific operation.

    Free space then slipped from 3.5T to 3.4T. The incremental backup was still writing to the same filesystem, but I did not prove it was the cause. I treated it as something to keep watching.

    Monitoring the concurrent backup

    I kept checking the same session. Output size grew across checks:

    SESSION_KEY STATUS       OUTPUT_BYTES_DI TIME_TAKEN_DISP
    ----------- ------------ --------------- ---------------
       REDACTED RUNNING          2.52T       21:14:51

    Earlier readings for that session went 2.43T, 2.45T, 2.46T, 2.47T, 2.49T, 2.50T, then 2.52T. Growing output tells you the job is moving. It does not tell you how close it is to finishing, because output bytes are not a percent-complete measure.

    What was and was not confirmed

    Confirmed:

    • Obsolete backups were deleted under the 5-day recovery window, with approval.
    • Free space on the filesystem rose from about 221G to about 3.4–3.5T.
    • The incremental backup was still RUNNING and producing output at the last check.

    Not captured:

    • Final completion of the incremental backup.
    • Resolution of every handle listed in the RMAN-06207 warnings.

    I would rather say that plainly than write a tidy ending the evidence does not support.

    Lessons and checklist

    1. Check what is writing to the filesystem before you start deleting.
    2. Run REPORT OBSOLETE and read it before DELETE OBSOLETE.
    3. Get the right approval for production deletes.
    4. Use RMAN to remove RMAN backups. Do not use rm.
    5. Treat RMAN-06207 as a repository mismatch to investigate, not noise.
    6. Remember that CROSSCHECK updates status. It does not delete.
    7. Read crosscheck output against the specific handles you care about.
    8. Trend free space after cleanup, especially while a backup is active.
    9. Revisit retention and capacity if the filesystem keeps reaching 98%.

    Disclaimer: this post describes one incident in one environment. Production backup cleanup needs environment-specific validation and proper authorization before you run anything similar. Hostnames, database names, paths and backup handles have been redacted.

  • AHF 26.9 Upgrade on RAC: Fixing a Remote Node SSH Failure

    Alhamdulillah. I recently upgraded Oracle AHF from 26.5.1.0.0 to 26.9.0.0.0 on a two-node RAC. Node 1 upgraded cleanly. Node 2 failed because the installer couldn’t authenticate over SSH as root. Here’s what happened and how I finished the job with a local upgrade.

    Hostnames and client-specific details are omitted.

    Environment

    • Platform: Linux x86-64
    • Setup: two-node Oracle RAC
    • Initial AHF version: 26.5.1.0.0
    • Target AHF version: 26.9.0.0.0
    • AHF home: /opt/oracle.ahf
    • AHF data directory: <oracle_base>/oracle.ahf/data

    The paths in the examples below are placeholders. Replace them with your actual installer and staging directories. Run the signature check and ahf_setup from the extracted installer directory, and run each command with the privileges the target paths require.

    The Problem

    I launched the cluster-wide installer from Node 1:

    cd /path/to/ahf_installer
    ./ahf_setup

    Node 1 upgraded fine. When it moved on to Node 2, the installer kept asking for the root password, then failed:

    [ERROR] : [node2] Failed to Upgrade AHF. Exit Status : 255

    The summary showed Node 1 on 26.9.0.0.0 and Node 2 still on 26.5.1.0.0. The installer still printed a general success message at the end, even though the cluster was only half upgraded.

    Lesson: read the per-node summary. Don’t trust the final success line.

    The Fix: Local Upgrade on Node 2

    Step 1: Copy and verify the package

    I copied the installer ZIP from Node 1 to Node 2 using an approved transfer method, then checked its integrity:

    unzip -t AHF-LINUX_v26.9.0.zip
    sha256sum AHF-LINUX_v26.9.0.zip

    The SHA-256 matched the checksum from the source node.

    Step 2: Extract and verify the signature

    mkdir -p /path/to/ahf_stage/26.9.0
    
    unzip -o AHF-LINUX_v26.9.0.zip \
      -d /path/to/ahf_stage/26.9.0
    
    cd /path/to/ahf_stage/26.9.0
    
    openssl dgst -sha256 \
      -verify ./oracle-tfa.pub \
      -signature ./ahf_setup.dat \
      ./ahf_setup

    Expected output:

    Verified OK

    Step 3: Run the local upgrade

    Oracle’s upgrade guide says to run ahf_setup as root. My account had authorized sudo privileges, so I ran the installer locally with sudo:

    sudo ./ahf_setup -local

    The installer detected the existing AHF installation and prompted for confirmation. The local upgrade completed successfully. Its final summary reported both Node 2 and Node 1 at AHF version 26.9.0.0.0 with status UPGRADED. I then verified the version and TFA status from both nodes.

    Step 4: Verify on both nodes

    sudo /opt/oracle.ahf/bin/tfactl version
    sudo /opt/oracle.ahf/bin/tfactl status

    Results on both nodes:

    • AHF version: 26.9.0.0.0
    • Matching build ID: 260900020260911121902
    • TFA status: RUNNING
    • Inventory status: COMPLETE
    • No version mismatch between nodes

    Observed Failure

    The installer couldn’t authenticate as root over SSH to the remote node. Oracle documents secure daemon socket communication for upgrading an existing AHF cluster; in this case, the installer nevertheless prompted for root SSH authentication.

    My logs show the immediate failure: the root SSH authentication attempt failed. They don’t show why the installer took that path or why the authentication failed, and I didn’t dig into it further.

    Best Practices

    • Confirm the target version and compatibility before you start.
    • Verify the installer checksum and signature before running it.
    • Run the installer as root, or with sudo if your account is authorized.
    • Confirm the required privileges and cluster communication prerequisites before upgrading. If unexpected SSH authentication prompts occur, investigate the issue rather than changing SSH settings without approval.
    • If remote authentication fails, use the documented local-upgrade procedure. Don’t make unapproved SSH or security changes.
    • Check the per-node summary and TFA status on every node.
    • Keep the installer logs and record the final version and build ID for change management.

    Conclusion

    ما شاء الله, both RAC nodes are now on AHF 26.9.0.0.0. The takeaway: a success message from the installer doesn’t guarantee every node was upgraded. Check each node’s status and confirm TFA is running before you close the change.

    Always follow the Oracle documentation and your organization’s change-management process for production work.

    References

  • Oracle EBS Workflow Mailer After an SMTP Migration: Why Mail Still Used the Old Relay

    Hostnames, IP addresses, usernames, email addresses, and notification IDs in this post are masked with # characters.

    Alhamdulillah, this investigation started with a simple question: after changing the SMTP server in Oracle E-Business Suite, why was mail still going through the old relay?

    It turned up three separate findings. The EBS Workflow Mailer configuration pointed to the new SMTP server. OS-level Sendmail still used the old relay. Some failed Workflow notifications were associated with a disabled recipient preference, and the reason for that preference is not yet established.

    This post documents the checks, the configuration change, and the evidence collected during validation. It is an interim investigation: the checks still open are listed in section 9.

    Environment

    • Oracle E-Business Suite R12.2
    • Oracle Database 11.2.0.4
    • Linux 7 application tier
    • Sendmail 8.14.7
    • systemd service management

    1. The initial problem

    The Workflow Mailer’s outbound SMTP server had been changed to the new server (####################). Network connectivity to the new server was successful, but the logs showed messages being relayed through the old relay (####################) before the Sendmail configuration change.

    At the same time, two notifications for one user showed MAIL_STATUS = FAILED.

    The first step was to verify the EBS configuration, then trace the actual mail path through the application and operating-system logs.

    2. Finding 1: EBS configuration and OS-level Sendmail did not match

    Verify the Workflow Mailer configuration

    SET LINESIZE 200
    COL parameter_name FORMAT A20
    COL parameter_value FORMAT A30
    COL last_update_date FORMAT A22
    SELECT RPAD(p.parameter_name,20) parameter_name,
    RPAD(NVL(v.parameter_value,'-'),30) parameter_value,
    TO_CHAR(v.last_update_date,'DD-MON-YY HH24:MI:SS')
    last_update_date
    FROM fnd_svc_comp_param_vals v,
    fnd_svc_comp_params_b p,
    fnd_svc_components c
    WHERE v.component_id = c.component_id
    AND v.parameter_id = p.parameter_id
    AND c.component_name = 'Workflow Notification Mailer'
    AND p.parameter_name = 'OUTBOUND_SERVER';

    OUTBOUND_SERVER showed the new SMTP server. The Sendmail log showed a different route:

    sendmail[####]: ##############:
    from=<wfmailer@#######################>,
    msgid=<########.####.#############.JavaMail.wfmailer@#######################>,
    proto=ESMTP, daemon=MTA,
    relay=####################### [###.###.###.###]
    sendmail[####]: ##############:
    to=<##################>, mailer=relay,
    relay=#################### [###.###.###.###],
    dsn=2.0.0, stat=Sent

    The logs confirmed that messages submitted to local Sendmail were forwarded through the old smart host. The sender and the JavaMail.wfmailer message ID point to messages generated by the Workflow Mailer. Oracle’s Workflow documentation describes the Mailer sending notification messages by SMTP to the SMTP server configured for it (see Outbound Notification Mailer Processing, from an older Workflow release), and notes that a UNIX host running Sendmail can serve as that SMTP server (see the Administrator’s Guide). The Mailer’s previous OUTBOUND_SERVER value was not captured, so the logs do not show why it handed these messages to local Sendmail. Further tracing was needed to establish the route used by the affected Workflow notifications.

    Check the Workflow Mailer process start time

    SET LINESIZE 200
    COL queue_name FORMAT A20
    COL status FORMAT A10
    COL os_pid FORMAT A10
    COL started FORMAT A22
    SELECT RPAD(q.concurrent_queue_name,20) queue_name,
    RPAD(NVL(p.process_status_code,'-'),10) status,
    RPAD(NVL(TO_CHAR(p.os_process_id),'-'),10) os_pid,
    TO_CHAR(p.process_start_date,'DD-MON-YY HH24:MI:SS')
    started
    FROM fnd_concurrent_processes p,
    fnd_concurrent_queues q
    WHERE p.concurrent_queue_id = q.concurrent_queue_id
    AND p.queue_application_id = q.application_id
    AND q.concurrent_queue_name = 'WFMLRSVC'
    AND p.process_status_code = 'A';

    The process had started 11 days before the parameter change. An OS-level check with ps -o pid,lstart,cmd -p <os_pid> showed the same start date.

    That raised the possibility that the Workflow Mailer had not been restarted after the change. The previous parameter value was not captured, though, so the start time alone could not show which SMTP server the running process had been using.

    Lesson: After changing Workflow Mailer parameters, check the active service process and follow the real message route in the logs. The database parameter alone doesn’t prove which server handled a message.

    Query note: last_update_date on the fnd_svc_components row is not the time a parameter changed. Use last_update_date on fnd_svc_comp_param_vals, as in the query above.

    3. Finding 2: Some failed notifications were associated with a disabled recipient preference

    Two notifications remained OPEN with MAIL_STATUS = FAILED. The recipient’s notification preference was DISABLED.

    SET LINESIZE 220
    COL recipient_role FORMAT A20
    COL mail_status FORMAT A12
    COL status FORMAT A10
    COL message_name FORMAT A30
    COL email_address FORMAT A30
    COL notif_pref FORMAT A12
    SELECT n.notification_id,
    RPAD(n.recipient_role,20) recipient_role,
    RPAD(NVL(n.mail_status,'-'),12) mail_status,
    RPAD(n.status,10) status,
    RPAD(NVL(n.message_name,'-'),30) message_name,
    RPAD(NVL(r.email_address,'-'),30) email_address,
    RPAD(NVL(r.notification_preference,'-'),12) notif_pref
    FROM wf_notifications n,
    wf_roles r
    WHERE n.notification_id IN (#######,#######)
    AND r.name = n.recipient_role;

    Example output:

    NOTIFICATION_ID RECIPIENT_ROLE MAIL_STATUS STATUS MESSAGE_NAME EMAIL_ADDRESS NOTIF_PREF
    --------------- --------------- ------------ ------- ----------------------- -------------------- ----------
    ####### ###### FAILED OPEN PO_PO_HAS_BEEN_APPROVE ################## DISABLED
    ####### ###### FAILED OPEN PO_REQ_APPROVED ################## DISABLED

    The preference was also found in WF_LOCAL_ROLES and traced to the Workflow MAILTYPE preference in FND_USER_PREFERENCES. Both notifications remained in the user’s Worklist.

    A DISABLED preference does not by itself explain a FAILED status. Oracle documents that when every address for a recipient is invalid and delivery fails, the Mailer sets the notification’s mail status to FAILED, sets the recipient’s preference to DISABLED, and notifies SYSADMIN (see the Oracle EBS technology blog). So DISABLED can be the result of an earlier delivery failure, not only a choice the user made.

    I did not check when or why this preference was set, or whether the failures began before it was set. I also have not yet confirmed whether these two messages ever reached Sendmail. Both checks are listed in section 9.

    4. Finding 3: Historical failures need to be separated from the migration issue

    Before attributing every failure to the migration, I collected a baseline of notification statuses.

    SET LINESIZE 200
    COL mail_status FORMAT A12
    COL cnt FORMAT 99999999
    SELECT RPAD(NVL(mail_status,'-'),12) mail_status,
    COUNT(*) cnt
    FROM wf_notifications
    WHERE mail_status IN ('MAIL','FAILED','ERROR')
    GROUP BY mail_status;
    Mail statusCountObservation
    MAIL0No records in this status
    FAILED156115 associated with disabled preferences, 39 with missing recipient roles, 2 canceled
    ERROR2,4252,255 created on one day for a single administrator role; the rest were older

    The dates showed that these records were not all from the migration period. The counts show association, not cause: a disabled preference can be a cause or a consequence of a failure. Historical records, missing roles, disabled preferences and SMTP delivery issues need separate investigation.

    5. Changing the Sendmail smart host

    The change was limited to the Sendmail configuration. These commands illustrate the procedure used here. Run them only after confirming the approved SMTP target, any maintenance requirements and the rollback plan.

    Pre-change checks

    date
    systemctl status sendmail --no-pager
    mailq
    grep -ni "SMART_HOST" /etc/mail/sendmail.mc
    grep -ni "^DS" /etc/mail/sendmail.cf
    nc -vz -w 5 #################### 25

    Back up the configuration

    cp -p /etc/mail/sendmail.mc \
    /etc/mail/sendmail.mc.bak_$(date +%Y%m%d_%H%M%S)
    cp -p /etc/mail/sendmail.cf \
    /etc/mail/sendmail.cf.bak_$(date +%Y%m%d_%H%M%S)

    Update the smart host

    Edit /etc/mail/sendmail.mc and change only the active SMART_HOST definition:

    define(`SMART_HOST', `####################')dnl

    Regenerate the configuration and verify:

    cd /etc/mail
    make
    grep -ni "^DS" /etc/mail/sendmail.cf

    Expected output:

    101:DS####################

    Restart Sendmail:

    systemctl restart sendmail
    systemctl status sendmail --no-pager

    The service returned to active (running) and was accepting connections.

    The change did not touch /etc/hosts, /etc/mail/access or /etc/hosts.allow. Those files serve other purposes and shouldn’t be edited just to change the smart host, unless a separate requirement justifies it.

    Rollback: restore sendmail.mc from its backup, run make, confirm the DS line, and restart Sendmail.

    6. Verify delivery through the new SMTP server

    A controlled test mail was sent from the application server to an approved test mailbox.

    echo "Test email from application server after SMTP migration" \
    | mail -s "SMTP Migration Test" ####################

    The relevant log entries:

    STARTTLS=client, relay=####################.,
    verify=FAIL, cipher=ECDHE-RSA-AES256-GCM-SHA384
    to=<####################>, mailer=relay,
    relay=####################. [###.###.###.###],
    dsn=2.0.0, stat=Sent

    ما شاء الله, the test message went through the new relay on the first attempt.

    What does stat=Sent mean? The next SMTP server accepted the message for delivery. It does not confirm arrival in the recipient’s inbox. Check the mailbox, and use the SMTP server’s message trace if delivery fails later.

    What does verify=FAIL mean? Sendmail did not verify the server certificate under its current settings, even though the SMTP transaction succeeded. Successful delivery is not proof that certificate validation is healthy, so review it separately with the mail or security team.

    7. What the investigation proved

    Confirmed by configuration and logs:

    • The EBS Workflow Mailer was configured with the new SMTP server.
    • OS-level Sendmail still had the old smart host before the change, and messages submitted to it were forwarded through that host.
    • The Sendmail configuration was updated, regenerated, and restarted successfully.
    • A controlled test message was relayed through the new SMTP server and accepted for delivery.
    • The two example notifications had MAIL_STATUS = FAILED, remained OPEN, and had a recipient preference of DISABLED.

    Not established by these checks:

    • Which SMTP server the running Workflow Mailer process was using internally before it was restarted, and why it handed messages to local Sendmail.
    • Whether the two failed notifications ever reached Sendmail.
    • When and why the recipient’s preference became DISABLED, and whether the failures began before it.
    • The cause of every historical FAILED or ERROR notification.
    • Whether the original affected notifications were delivered after the Sendmail change.
    • Whether the recipient received the test email.
    • The cause of the STARTTLS certificate-verification warning.

    A successful test email validates one segment of the mail path. The original Workflow notification still needs its own test.

    8. Practical lessons

    1. Check both EBS and OS-level SMTP settings. The Workflow Mailer parameter and the Sendmail smart host can differ.
    2. Compare the parameter change time with the process start time. Restart the Workflow Mailer component when the change procedure requires it, and confirm the new start time.
    3. Trace a real message end to end. Use the notification record, the Mailer logs, the Sendmail logs and recipient confirmation.
    4. Don’t assume a failed notification is either an SMTP problem or a preference problem. A disabled preference can be a cause or a consequence of a delivery failure, so check when it was set, along with the recipient role, email address and notification status.
    5. Capture a baseline before changing anything. Old FAILED and ERROR records can have unrelated causes.
    6. Verify the handoff and the final delivery separately. stat=Sent is evidence of SMTP acceptance, not of inbox delivery.
    7. Review certificate verification on its own. Successful delivery doesn’t remove the need to investigate TLS warnings.

    9. Status and remaining checks

    The Sendmail change is complete and the test message was accepted by the new relay. These checks are still open:

    1. Failed notifications: search the Sendmail log for the affected recipient to establish whether the two failed messages ever reached Sendmail.
    2. Preference history: establish when and why the recipient’s MAILTYPE preference became DISABLED (who last updated it, and whether the first FAILED notification came before or after), and whether SYSADMIN received an invalid-address notice.
    3. Workflow Mailer process: verify the active WFMLRSVC process against the parameter change time, and restart the component under the approved change procedure if needed.
    4. End-to-end Workflow test: submit a test notification, then check the Mailer log and the Sendmail log to confirm it was relayed through the new server.
    5. Certificate verification: investigate verify=FAIL separately with the mail or security team.

    Until those checks are done, this post is an interim investigation. It does not claim that the original Workflow notifications have been fixed.

    Conclusion

    Changing the SMTP server in Oracle EBS may not be the whole job. OS-level Sendmail has its own smart-host setting, and it needs checking when the mail logs show messages leaving through an unexpected relay.

    The Sendmail test confirmed that the new relay accepts mail from the application server. The checks in section 9 will show whether the Workflow Mailer path itself works end to end, and why the affected notifications failed.

    Disclaimer: This article is based on a troubleshooting scenario. All hostnames, IP addresses, usernames, email addresses and notification IDs are masked. Validate all commands and configuration changes against your own environment and change-management procedures before using them in production.

  • Oracle EBS R12.2 DualFS RapidClone: FMW Prerequisite Failures, RPMDB Corruption and Stale Inventory

    Alhamdulillah, this post documents the issues hit during an EBS R12.2 QA application-tier refresh and how each was isolated. Server names, paths and identifiers are generic examples.

    Environment (generic)

    ComponentExample
    App serverqa-app-server01
    DB serverqa-db-server01
    EBS environmentQA_EBS
    Application base/u01/apps
    Pairs file/u01/cloning/pairs/qa_apps_pairs.txt
    Central inventory/opt/oraInventory

    Background

    A DualFS clone recreates both fs1 and fs2. Per the cloning procedure used here, the old fs2, inst and FMW_Home were moved aside and removed first:

    cd /u01/apps/
    mv fs2 fs2_old
    rm -rf fs2_old &
    
    cd fs1
    mv inst inst_old
    mv FMW_Home FMW_Home_old
    rm -rf inst_old FMW_Home_old &

    Cleanup steps should follow your own environment’s cloning document.

    Symptom

    adcfgclone.pl failed at the FMW prerequisite stage:

    ERROR: Failed to execute FMW pre-requisite check

    Re-running would not have helped. The prerequisite check reads OS state, so that is where the investigation started.

    cat /etc/os-release
    rpm --verifydb
    rpm -qa | grep -E 'compat-libcap1|compat-libstdc'

    Issue 1: RPM database corruption

    On one app server, rpm --verifydb returned Berkeley DB errors:

    BDB0682 Page ... bad prev_pgno
    BDB0683 Page ... overflow item incomplete
    Packages: BDB0090 DB_VERIFY_BAD

    Package queries also showed rpmdbNextIterator: skipping h# ... and region trailer: BAD.

    RPMDB corruption was identified and the package state was subsequently validated. If the RPM database is unhealthy, package-based prerequisite results can be incomplete or misleading. Running rpm --verifydb early is a useful way to identify this condition before spending time troubleshooting the Oracle prerequisite scripts.

    Issue 2: Missing compatibility packages

    Two packages were missing: compat-libcap1 and compat-libstdc++-33. After confirming repository availability, both were installed with dnf install, then the RPM database was verified again.

    A similar QA server passed the check without this problem, so package state can differ between servers that look identical.

    Issue 3: refhost.xml OL7 block on an OL8 target

    The target was Oracle Linux 8, but the first OS block in refhost.xml was defined for Oracle Linux 7:

    /u01/apps/fs1/EBSapps/comn/clone/prereq/webtier/Scripts/prereq/linux64/refhost.xml
    <VERSION VALUE="7"/>

    Only that block was changed to VALUE="8". A global sed replacement is risky because the file contains multiple OS definitions. Back up the file, identify the applicable block, change only that, and validate the XML.

    Issue 4: Stale Oracle Central Inventory

    Removing FMW_Home from disk does not remove it from the central inventory. Entries such as these were still registered after the directories were gone:

    /u01/apps/fs1/FMW_Home/oracle_common
    /u01/apps/fs1/FMW_Home/webtier
    /u01/apps/fs1/FMW_Home/Oracle_EBS-app1

    Documented cloning step. The cloning document’s inventory cleanup applies to the target database server (check /etc/oraInst.loc, remove the DB home entry from ContentsXML/inventory.xml). It does not cover resetting the application-server inventory, so the app-server reset described here is not part of the standard cloning steps.

    Before any inventory change: confirm the active inventory via /etc/oraInst.loc, preserve a copy, then apply the approved procedure. The existing inventory was kept as a backup. Note that the first mv below is conditional: run it only if /opt/oraInventory_old already exists.

    # Only if /opt/oraInventory_old already exists:
    mv /opt/oraInventory_old /opt/oraInventory_old_backup
    
    mv /opt/oraInventory /opt/oraInventory_old
    mkdir /opt/oraInventory
    chown oracle:oinstall /opt/oraInventory

    Issue 5: EXECUTE_FMW_SYS_PREREQS

    The cloning procedure sets this variable before the DualFS run:

    export EXECUTE_FMW_SYS_PREREQS=false
    echo $EXECUTE_FMW_SYS_PREREQS

    This skips the FMW OS prerequisite execution. It was set here only after the failures above had been investigated, and only because the procedure specifies it. It is not a general substitute for fixing prerequisite failures.

    Issue 6: SSH disconnect during a multi-hour clone

    RapidClone can run for hours, and the procedure calls for a screen session (or VDI). During this exercise the SSH session dropped mid-run.

    screen -S rapidclone
    cd /u01/apps/fs1/EBSapps/comn/clone/bin
    export EXECUTE_FMW_SYS_PREREQS=false
    perl adcfgclone.pl component=appsTier \
    pairsfile=/u01/cloning/pairs/qa_apps_pairs.txt \
    dualfs=yes

    After the disconnect, check before restarting anything:

    screen -ls
    screen -r <session>

    If the original process is still running, a second adcfgclone.pl would only add complications.

    Result

    After the identified OS, package, prerequisite and inventory issues were addressed, the DualFS clone completed and created both fs1 and fs2.

    ما شاء الله

    The same approach worked on the second QA environment. This establishes that the DualFS RapidClone completed, not that the entire QA refresh is finished: post-clone configuration is separate, and the procedure says not to start services at the end of the clone until the required post-clone steps are completed.

    Summary

    FindingLayerAction
    FMW prerequisite failureOS / packagesInvestigated underlying checks
    RPMDB corruptionOSIdentified the corruption and validated the package state after remediation
    Missing compat RPMsOSInstalled required packages
    OL7 block on OL8 targetPrerequisite configCorrected the applicable block only
    Stale FMW homes in inventoryOracle InventoryBacked up the existing inventory, then applied the approved remediation
    Long-running cloneSessionRan inside screen

    Suggested pre-clone checklist

    cat /etc/os-release
    rpm --verifydb
    rpm -qa | grep -E 'compat-libcap1|compat-libstdc'
    cat /etc/oraInst.loc
    ls -ld /u01/apps/fs1 /u01/apps/fs2
    ls -l /u01/apps/fs1/EBSapps/comn/clone/bin/adcfgclone.pl

    Post-clone

    RapidClone success is not the end of the refresh. The cloning procedure continues with custom environment configuration, AutoConfig, WebLogic configuration, Concurrent Manager/MWA node configuration, shared filesystem setup and further AutoConfig runs, followed by application validation.

    Takeaway

    RapidClone is often where infrastructure problems become visible, not where they start. When it fails, check the layers underneath before rerunning:

    OS → RPM database → packages → prerequisite config → Oracle Inventory → filesystem → RapidClone → post-clone configuration

    Examples use generic names. No real server names, IP addresses, domains, company names or screenshots are included.

  • Oracle 19c Data Guard: Recovering UNNAMED Datafiles on a Multitenant Physical Standby

    Alhamdulillah.

    Oracle Data Guard physical standbys keep redo synchronized automatically — until the primary adds a datafile that the standby can’t place on disk. When STANDBY_FILE_MANAGEMENT=MANUAL, the standby refuses to guess where the new file should live. Managed Standby Recovery stops instead, leaving the control file ahead of the actual datafiles and the standby parked at a consistent SCN.

    This post walks through a real 19c multitenant incident: MRP0 hit ORA-01274 after a new datafile couldn’t be added, recovery stalled, and the fix required creating the missing file inside the correct pluggable database container, then resuming and verifying redo apply. In this incident, the missing datafile belonged to PROD. Creating the file from within the owning PDB resolved the placeholder, after which Redo Apply could be restarted from CDB$ROOT.

    Failure Diagnosis

    The alert log during redo apply:
    Recovery of Online Redo Log: Thread 1 Group 4 Seq 105902 Reading mem 0
    Mem# 0: /uora/PROD/db/product/19.0.0/dbs/broken3
    2025-05-12T08:49:56.027319-04:00
    PROD(3):File #433 added to control file as ‘UNNAMED00433’ because
    PROD(3):the parameter STANDBY_FILE_MANAGEMENT is set to MANUAL
    PROD(3):The file should be manually created to continue.
    PR00 (PID:2796228): MRP0: Background Media Recovery terminated with error 1274
    2025-05-12T08:49:56.092976-04:00
    Errors in file /uora/PROD/db/diag/rdbms/proddr/cdbPROD/trace/cdbPROD_pr00_2796228.trc:
    ORA-01274: cannot add data file that was originally created as
    ‘/uora/PROD/data/proddata/users02.dbf’
    PR00 (PID:2796228): Managed Standby Recovery not using Real Time Apply
    Recovery interrupted!
    2025-05-12T08:49:57.933554-04:00
    Recovery stopped due to failure in applying recovery marker (opcode 17.30).
    Datafiles are recovered to a consistent state at change 36278361292
    but controlfile could be ahead of datafiles.
    Stopping change tracking


    Three things happening in sequence:

    1. **Control file registered a file that doesn’t exist.** The redo stream carried a datafile creation from the primary. The standby’s control file logged it — but because STANDBY_FILE_MANAGEMENT=MANUAL, the standby recorded it as UNNAMED00433 instead of creating it.

    2. **Recovery stopped on the recovery marker.** Opcode 17.30 is the file operation that couldn’t be satisfied. The standby parked at SCN 36278361292 — a point where datafiles are internally consistent, but the control file believes file 433 exists when it doesn’t.

    3. **MRP0 exited.** The managed standby process shut down cleanly. The alert log shows “not using Real Time Apply,” indicating recovery was interrupted and the standby could not continue applying the current redo stream.

    **Root cause:** Configuration, not corruption. STANDBY_FILE_MANAGEMENT=MANUAL means every new primary datafile must be created manually on the standby. With AUTO and proper DB_FILE_NAME_CONVERT / PDB_FILE_NAME_CONVERT setup, new files appear automatically. This environment chose MANUAL, so a routine tablespace addition on the primary became a recovery outage on the standby.

    ## Recovery Workflow

    MRP0 stops → Query UNNAMED files → Switch to PDB → Create datafile → Resume MRP → Verify

    ## Step 1 — Locate the UNNAMED File

    Confirm the standby’s role and find the placeholder. Run from CDB$ROOT:


    SET ECHO OFF PAGESIZE 60 LINESIZE 120 TRIMSPOOL ON
    COL NAME FORMAT A50
    SQL> SELECT name, open_mode, database_role FROM v$database;
    NAME OPEN_MODE DATABASE_ROLE
    ——— ——————– —————-
    CDBSTBY MOUNTED PHYSICAL STANDBY
    SQL> SELECT FILE#, NAME FROM V$DATAFILE WHERE NAME LIKE ‘%UNNAMED%’;
    FILE# NAME
    ———- ————————————————–
    433 /u01/app/oracle/product/19.0.0/dbhome_1/dbs/UNNAMED00433


    File number is 433. Which PDB owns it? Use CON_ID:


    COL CON_ID FORMAT 9999
    COL FILE# FORMAT 9999
    COL NAME FORMAT A50
    SQL> SELECT con_id, file#, name FROM V$DATAFILE WHERE file# = 433;
    CON_ID FILE# NAME
    ———- —— ————————————————–
    3 433 /u01/app/oracle/product/19.0.0/dbhome_1/dbs/UNNAMED00433


    CON_ID = 3 is PROD. That’s where the fix must run.

    ## Step 2 — PDB Recovery: Create the File in the Right Container

    From CDB$ROOT, the command appeared to succeed:


    SQL> ALTER DATABASE CREATE DATAFILE ‘UNNAMED00433’
    AS ‘/uora/PROD/data/proddrdata/users02.dbf’;
    Database altered.
    “`

    But checking from the PDB showed the placeholder still registered:


    SQL> ALTER SESSION SET CONTAINER = PROD;
    Session altered.
    SQL> SELECT FILE#, NAME FROM V$DATAFILE WHERE NAME LIKE ‘%UNNAMED%’;
    FILE# NAME
    ———- ————————————————–
    433 /uora/PROD/db/product/19.0.0/dbs/UNNAMED00433


    After switching to the PROD container and reissuing the command:


    SQL> ALTER DATABASE CREATE DATAFILE ‘UNNAMED00433’
    AS ‘/uora/PROD/data/proddrdata/users02.dbf’;
    Database altered.
    SQL> SELECT FILE#, NAME FROM V$DATAFILE WHERE NAME LIKE ‘%UNNAMED%’;
    no rows selected


    **Important:** Validate this behavior against Oracle 19c documentation and test in non-production before applying to your standby.

    ## Step 3 — Redo Apply Resumption


    SQL> ALTER SESSION SET CONTAINER = CDB$ROOT;
    Session altered.
    SQL> ALTER DATABASE RECOVER MANAGED STANDBY DATABASE
    USING CURRENT LOGFILE DISCONNECT FROM SESSION;
    Database altered.
    SQL> SELECT PROCESS, STATUS, THREAD#, SEQUENCE# FROM V$MANAGED_STANDBY;
    PROCESS STATUS THREAD# SEQUENCE#
    ———- ————— ——- ———
    MRP0 APPLYING_LOG 1 105902
    ARCH CLOSING 1 105905
    RFS IDLE 1 105906


    MRP0 is back in APPLYING_LOG.

    ## Step 4 — Expect More: The Second UNNAMED File

    Recovery resumed and encountered another placeholder:

    “`sql
    SQL> ALTER SESSION SET CONTAINER = PROD;
    SQL> SELECT FILE#, NAME FROM V$DATAFILE WHERE NAME LIKE ‘%UNNAMED%’;
    FILE# NAME
    ———- ————————————————–
    435 /uora/PROD/db/product/19.0.0/dbs/UNNAMED00435
    SQL> ALTER DATABASE CREATE DATAFILE ‘UNNAMED00435’
    AS ‘/uora/PROD/data/proddrdata/transaction_table_16.dbf’;
    Database altered.


    Expect a loop. Every datafile added on the primary after the gap will appear as another UNNAMED entry. Grep the alert log for the full backlog first:


    grep -i ‘unnamed’ alert_cdbstby.log | head -20
    grep ‘ORA-01274’ alert_cdbstby.log | wc -l


    ## Recovery Verification

    Once placeholders are gone, resume recovery:


    ALTER SESSION SET CONTAINER = CDB$ROOT;
    ALTER DATABASE RECOVER MANAGED STANDBY DATABASE
    USING CURRENT LOGFILE DISCONNECT FROM SESSION;
    “`

    Verify:


    SELECT con_id, file#, name FROM V$DATAFILE WHERE name LIKE ‘%UNNAMED%’;
    SELECT process, status, thread#, sequence# FROM V$MANAGED_STANDBY WHERE process LIKE ‘MRP%’;
    SELECT * FROM V$DATAGUARD_STATS;


    Clean results: zero UNNAMED rows, MRP0 in APPLYING_LOG, apply lag returning to normal.

    ## Alternative: Restore from Backup

    If redo is unavailable or purged:

    1. Identify primary backup with missing file
    2. Restore to standby location
    3. Register with control file via RMAN
    4. Resume recovery

    Follow Oracle RMAN and Data Guard documentation for your configuration.

    ## Lessons Learned

    **Decide STANDBY_FILE_MANAGEMENT deliberately.** MANUAL works for locked-down environments. AUTO prevents this class of manual intervention when file naming and storage support it. ما شاء الله — the infrastructure, when well-designed, removes recovery work.

    **Session container context can affect recovery steps.** In this incident, CREATE DATAFILE from CDB$ROOT appeared to succeed but didn’t resolve the placeholder until run from PROD PDB. Validate against Oracle 19c documentation and test in non-production.

    **Expect a loop.** Every datafile added after the gap arrives as another UNNAMED entry. Grep the alert log for full backlog first.

    **Verify before closing.** Confirm zero UNNAMED files, MRP0 running, settled lag before closing incident.

    ## Conclusion

    ORA-01274 on a physical standby is a configuration boundary, not data loss. This incident resolved via CREATE DATAFILE in the PROD PDB, followed by managed recovery restart from CDB$ROOT. Before applying: Verify steps against Oracle 19c documentation, test in non-production, verify standby status and lag.

  • Oracle Database 19c July 2026 Release Update Patching: Real-World Walkthrough

    Overview

    This article documents a complete Oracle Database 19c Standard Edition 2 patch cycle from baseline validation through final SQL registry confirmation. The database was patched from 19.31.0.0.0 to 19.32.0.0.260721 using the July 2026 release update bundle.

    The value of this walkthrough is not just the successful outcome, but the operational details, timing, troubleshooting observations, and the superset/subset patch behavior that often confuses teams in real patching scenarios.

    Environment Baseline

    Database: Production DB Instance
    Role: PRIMARY
    Open Mode: READ WRITE
    Database Version: 19.31.0.0.0
    Edition: Standard Edition 2
    OPatch Version (at session start): 12.2.0.1.52
    Database Home: /oracle/app/product/db_home/19c/instance
    Grid Home: /oracle/app/product/grid/19c_home

    OPatch had been upgraded to 12.2.0.1.52 prior to beginning the patching sequence.

    Section 1: Pre-Patching Validation

    Database Status Check

    SQL> select name, open_mode, database_role from v\$database;
    
    NAME      OPEN_MODE   DATABASE_ROLE
    --------- ----------- ----------------
    PRODDB    READ WRITE  PRIMARY
    

    Observation: Database is healthy and accessible at start.

    Existing Patches

    The database carried three active patches from the April/July 2026 cycle:

    38906621  OJVM RELEASE UPDATE: 19.31.0.0.260421
    39039430  OCW RELEASE UPDATE 19.31.0.0.0
    39034528  Database Release Update: 19.31.0.0.260421
    

    Pre-Existing Invalid Objects

    The following query revealed 10 invalid objects, all under the DEVELOPMENT schema with modification dates ranging from 2021–2025:

    SQL> select object_name, object_type, owner, created 
         from dba_objects 
         where status = 'INVALID' 
         order by owner, object_name;
    
    OBJECT_NAME         OBJECT_TYPE   OWNER        CREATED
    ------------------- ------------- ------------ ----------
    <object list>       <type>        DEVELOPMENT  2021–2025
    

    Importance of this baseline: These invalid objects predate the patch session. Documenting them prevents incorrectly attributing them to patching activity. At post-patching validation, we will confirm they remain unchanged.

    Section 2: Crontab Protection

    Before any Grid or database activity, the existing Oracle crontab was reviewed and protected.

    The crontab contained:

    • RMAN backups
    • Archive backups
    • Health checks
    • FRA space checks
    • Log cleanup routines
    • CPU alerting
    • TechBoost startup

    Crontab Protection Command:

    /usr/bin/crontab -l | /bin/sed 's/^/##JULY_2026##&/g' | /usr/bin/crontab
    

    This prefixes every crontab entry with ##JULY_2026##, effectively disabling all scheduled jobs while preserving them for rollback. This is a critical operational detail often overlooked in patching procedures. The surrounding infrastructure — backups, health checks, monitoring — must be accounted for, not just the Oracle binaries.

    Section 3: Database Shutdown

    The database was cleanly shut down before any Grid Home maintenance:

    SQL> shutdown immediate;
    
    Database closed.
    Database dismounted.
    ORACLE instance shut down.
    

    TNS processes were verified afterward to confirm a clean state.

    Section 4: CRS/HAS Lifecycle Management

    Initial CRS Status Check

    $ ./crsctl check crs
    

    All major CRS components reported online.

    Stopping HAS

    $ ./crsctl stop has
    
    CRS-4133: Oracle High Availability Services has been stopped.
    

    Subsequent check:

    $ ./crsctl check crs
    
    CRS-4639: Could not contact Oracle High Availability Services
    

    Restarting HAS

    $ ./crsctl start has
    
    CRS-4638: Oracle High Availability Services is online
    

    Initial state after restart (first check):

    CRS-4638: Oracle High Availability Services is online
    CRS-4535: Cannot communicate with Cluster Ready Services
    CRS-4530: Communications failure contacting Cluster Synchronization Services daemon
    CRS-4534: Cannot communicate with Event Manager
    

    Key observation: An immediate crsctl check crs after crsctl start has should NOT be interpreted as a failure. CRS components require time to establish quorum and synchronize.

    Final state (repeated checks):

    CRS-4638: Oracle High Availability Services is online
    CRS-4537: Cluster Ready Services is online
    CRS-4529: Cluster Synchronization Services is online
    CRS-4533: Event Manager is online
    

    Teaching point: This is a real troubleshooting scenario. Patience during CRS startup is required. A few seconds of “Cannot communicate” messages are normal before full synchronization.

    Section 5: Grid Infrastructure Patching — Node 1

    Patch Bundle

    /backup/install/JULY2026/39618711/39467003
    

    OPatchAuto Execution

    \$GRID_HOME/OPatch/opatchauto apply \
    /path/to/patch/bundle/39618711/39467003 \
    -oh \$GRID_HOME
    

    Session Start: 20:17:54

    Session Flow:

    1. Prerequisite checks → PASSED
    2. Patch validation → PASSED
    3. CRS brought down
    4. Binary patch applied
    5. rootadd_rdbms.sh executed
    6. CRS restarted

    Patches Applied

    39472050
    39503034
    39526364
    

    Patches Skipped

    39107825
    39107855
    

    Reason: Not required for this Grid Home. OPatchAuto intelligently determines applicability per Grid Home.

    Session End: 20:39:13
    Duration: 21 minutes, 13 seconds

    Section 6: Grid Infrastructure Patching — Node 2

    OPatchAuto Execution (Node 2)

    Same Grid Home, same patch bundle, Node 2:

    \$GRID_HOME/OPatch/opatchauto apply \
    /path/to/patch/bundle/39618711/39467003 \
    -oh \$GRID_HOME
    

    Session ID: CHM5
    Session Start: 20:53:18

    Session Flow:

    1. Prerequisite checks → PASSED
    2. Patch validation checks → PASSED
    3. CRS brought down
    4. Binary patch applied
    5. rootadd_rdbms.sh executed
    6. CRS restarted

    Patches Applied (Node 2)

    39472050
    39503034
    39526364
    

    Patches Skipped (Node 2)

    39107825
    39107855
    

    Reason: Same as Node 1 — not required for this Grid Home configuration.

    Session End: 21:18:43
    Duration: 25 minutes, 15 seconds

    Section 7: Database Home Patching

    OPatchAuto Against Database Home

    \$ORACLE_HOME/OPatch/opatchauto apply \
    /path/to/patch/bundle/39618711/39467003 \
    -oh \$ORACLE_HOME
    

    Prerequisite Checks

    Patch applicability verified successfully
    Patch validation checks successfully completed
    

    Patch Application Log

    Prepatch operation completed successfully
    Binary patch applied successfully
    rootadd_rdbms.sh successfully executed
    Postpatch operation completed successfully
    

    Patches Skipped

    The following were skipped because they are not applicable to the database target type:

    39503034
    39107825
    39107855
    
    Reason: This patch is not applicable to this specified target type - "rac_database"
    

    Important teaching point: A patch bundle often contains patches for multiple target types (Grid, database, RAC, single-instance, etc.). OPatchAuto filters and applies only those applicable to the target. A skipped patch is not a failure condition; it is correct filtering behavior.

    Section 8: Manual OJVM Patching — The Superset/Subset Moment

    This is the most valuable part of the patching narrative.

    Applying OJVM Patch 39222882

    opatch apply -id 39222882
    

    Confirmation:

    Patch 39222882 successfully applied.
    
    Sub-set patch [38906621] has become inactive
    due to the application of a super-set patch [39222882].
    

    Understanding Superset/Subset Behavior

    Previous OJVM patch:

    38906621  OJVM 19.31.0.0.260421
    

    New OJVM patch:

    39222882  OJVM 19.32.0.0.260721
    

    Patch 39222882 is a superset of 38906621. When the superset is applied, OPatch automatically marks the old subset patch as inactive. The old patch is still in the patch inventory, but is no longer in effect.

    This is critical to understand: you will not see an explicit opatch rollback 38906621 command. Instead, the superset patch absorbs the functionality, and the subset becomes inactive. The SQL layer (datapatch) later rolls back the subset formally, but the binary layer handles it through superset supersession.

    Section 9: Database Startup After OJVM Binary Patch

    After applying 39222882, the database was started:

    SQL> startup;
    
    Database mounted.
    Database opened.
    

    SQL*Plus version verification:

    Version 19.32.0.0.0
    

    The database came up cleanly on the new binary.

    Section 10: datapatch — SQL Layer Patch Application

    The SQL layer patching is where the logical consistency is established:

    cd \$ORACLE_HOME/OPatch
    ./datapatch -verbose
    

    datapatch Analysis

    • Old OJVM patch: 38906621
    • New OJVM patch: 39222882
    • New RU: 39472050

    Installation Queue

    Based on the above, datapatch constructed the following queue:

    Rollback:

    38906621
    

    Apply:

    39472050
    39222882
    

    Execution Results

    Patch 38906621 rollback: SUCCESS
    Patch 39472050 apply: SUCCESS
    Patch 39222882 apply: SUCCESS
    

    No errors in the corresponding SQL patch logs.

    Teaching point: This is the orchestration that many DBAs find confusing. The binary layer and the SQL layer operate in sequence:

    1. Binary layer (OPatchAuto): Applies 39222882, marks 38906621 as inactive
    2. SQL layer (datapatch): Detects this change, formally rolls back 38906621 from the data dictionary, then applies 39472050 and 39222882 at the SQL level

    The two layers must synchronize. datapatch handles this automatically, but understanding the sequence prevents misinterpretation of the logs.

    Section 11: Final Patch Levels

    opatch lspatches Output

    39222882;OJVM RELEASE UPDATE: 19.32.0.0.260721
    39526364;OCW RELEASE UPDATE 19.32.0.0.0
    39472050;Database Release Update: 19.32.0.0.260721
    

    State Transition Summary

    ComponentBeforeAfter
    Database RU19.31.0.0.26042119.32.0.0.260721
    OJVM19.31.0.0.26042119.32.0.0.260721
    OCW19.31.0.0.019.32.0.0.0

    Section 12: SQL Patch Registry Verification

    Final DBA_REGISTRY_SQLPATCH output:

    38906621  ROLLBACK  SUCCESS  31-AUG-26 09:02:48 PM
    39222882  APPLY     SUCCESS  31-AUG-26 09:02:59 PM
    39472050  APPLY     SUCCESS  31-AUG-26 09:03:55 PM
    

    This chronological sequence provides irrefutable proof:

    1. Old OJVM patch rolled back at 09:02:48 PM
    2. New OJVM patch applied 11 seconds later at 09:02:59 PM
    3. Database RU applied at 09:03:55 PM

    No conflicts. Clean transition.

    Section 13: Final Component Validation

    DBA_REGISTRY Check

    SQL> select comp_name, status 
         from dba_registry 
         order by comp_name;
    
    COMP_NAME              STATUS
    ---------------------- -------
    CATALOG                VALID
    CATPROC                VALID
    JAVAVM                 VALID
    XML                    VALID
    CATJAVA                VALID
    CONTEXT                VALID
    XDB                    VALID
    ORDIM                  VALID
    APEX                   VALID
    

    All critical components report VALID. Optional components show OPTION OFF where applicable.

    Pre-Existing Objects Revisited

    The 10 invalid objects identified in pre-patching validation remained unchanged — still invalid, still dated 2021–2025, still under the DEVELOPMENT schema. No new invalid objects were introduced by patching.

    Section 14: Lessons from Real Execution

    Not everything is shown in the logs. During the session, there was an operator mistake:

    After exiting SQL*Plus, the following commands were inadvertently entered at the bash prompt instead of within SQL*Plus:

    Set lines 230
    col ...
    select ...
    

    Result:

    bash: Set: command not found
    col: bad usage
    bash: syntax error near unexpected token
    

    This is not an Oracle patching failure. It was simply commands executed in the wrong shell context. The log was corrected, commands were re-entered in SQL*Plus, and execution continued without issue.

    Why include this: This makes the article realistic. Patching sessions involve multiple shells, multiple environments, and context switching. Showing the actual mistake and recovery is more valuable than hiding it. It serves as a quiet reminder to teams that operational discipline — knowing which shell you’re in, which home you’ve sourced, which user you’re running as — is as important as the patch commands themselves.

    Section 15: Conclusion

    The patching session was completed successfully from baseline validation through final registry confirmation. Total elapsed time across all phases was approximately 46 minutes (20:17 to 21:18, accounting for Node 2 completion).

    Key takeaways:

    1. Baseline matters: Document pre-existing conditions (invalid objects, patch levels, cron jobs) to avoid misattribution later.
    2. Infrastructure protection: Patching isn’t just about binaries. Protect cron jobs, backups, and monitoring to prevent unintended outages during the maintenance window.
    3. CRS behavior is asynchronous: After crsctl start has, components come online gradually. Immediate crsctl check crs showing “Cannot communicate” is normal and not actionable.
    4. Patch applicability is intelligent: OPatchAuto skips patches that don’t apply to the target type. This is not a failure.
    5. Superset/subset is binary-layer behavior: When a superset patch is applied, the subset becomes inactive at the binary layer. The SQL layer (datapatch) handles the formal rollback.
    6. datapatch orchestrates across layers: The SQL layer patch tool detects binary changes and constructs the correct rollback/apply queue automatically. Trust the tool.
    7. Real execution has missteps: Shell context errors, timing observations, and troubleshooting moments are part of the work. Documenting them makes the guidance actionable for other teams.

    The database is now on 19.32.0.0.260721 with all components validated.

  • Podcast Episode: Oracle EBS R12.2 `adop phase=fs_clone` Fails with JSAFE_PaddingException: Invali

    Pip: If you've ever watched a file system clone grind to a halt at ninety percent and thought "well, at least it's almost done," Syed Anwar Ahmed has a post that will gently correct your optimism.

    Mara: This episode covers one of those Oracle EBS R12.2 maintenance failures where the error message on the surface points one direction and the real problem is buried several log files deeper — specifically inside WebLogic credential configuration during a patch file system clone.

    Pip: Let's start with what actually went wrong during that fs_clone operation, and why the obvious error wasn't the guilty party.

    —

    Pip: If you've ever watched a file system clone grind to a halt at ninety percent and thought "well, at least it's almost done," Syed Anwar Ahmed has a post that will gently correct your optimism.

    Mara: This episode covers one of those Oracle EBS R12.2 maintenance failures where the error message on the surface points one direction and the real problem is buried several log files deeper — specifically inside WebLogic credential configuration during a patch file system clone.

    Pip: Let's start with what actually went wrong during that fs_clone operation, and why the obvious error wasn't the guilty party.

    When the Clone Lies to Your Face

    Pip: The setup here is a routine EBS R12.2 maintenance cycle — adop phase=fs_clone is supposed to rebuild the patch file system, and instead it keeps failing. The surface error looks like an edition problem, which sends you hunting in entirely the wrong direction.

    Mara: Right, and the post is explicit about this misdirection. The initial message the operation reported was "ERROR: Unable to set edition. Invalid edition type : PATCH," followed by "adclone.pl did not go through successfully. EXIT STATUS: 1."

    Pip: So you see "Invalid edition type : PATCH" and you start thinking about edition configuration — which is exactly the wrong rabbit hole, because the actual failure is a WebLogic password decryption error sitting deeper in the logs.

    Mara: The WLST logs showed the real exception: the failure chain ran from txkSetAppsLibsTarget.py through setNodeManagerCredentials and getNodeManagerPassword, landing on "com.rsa.jsafe.JSAFE_PaddingException: Invalid padding." WebLogic could not decrypt the Node Manager password while configuring fs2.

    Pip: What this means in practice is that the clone stopped because of a credential encryption mismatch — not disk space, not port conflicts, not anything the OS was doing. The post confirms all three of those were ruled out: filesystem space was adequate, ports were acquired cleanly, and OS logs showed no OOM kills or Java process terminations.

    Mara: The ninety percent progress point on the FMW Home cloning step was a location marker, not a cause. The post is careful to say that figure shows where the clone stopped, not why.

    Pip: And the fix, once the actual cause was identified, is a five-step sequence: correct boot.properties, restart WebLogic, run AutoConfig on the RUN file system, run Preclone on the RUN file system, then rerun fs_clone with force=yes.

    Mara: The post closes with a pointed takeaway — messages like "adclone.pl did not go through successfully" only tell you the clone failed. The actionable diagnosis requires going into the FSCloneApplyAppsTier and WLST logs to find the component that actually broke. The JSAFE_PaddingException pattern specifically signals a WebLogic credential and encryption configuration issue, not a resource problem.

    Pip: Worth noting: the post flags that this resolution is environment-specific. JSAFE_PaddingException during EBS cloning can have different underlying causes, so reviewing the detailed logs before applying this fix elsewhere is the actual lesson — not just copying the five steps.

    Mara: Exactly the kind of maintenance incident where the log discipline matters as much as the fix itself.


    Pip: The real takeaway is that generic failure messages are just the beginning of the investigation, not the answer.

    Mara: Dig into the WebLogic and WLST logs — that's where the actual story lives. More from the blog next time.

  • Oracle EBS R12.2 `adop phase=fs_clone` Fails with JSAFE_PaddingException: Invalid Padding

    Alhamdulillah.

    Introduction

    During a routine Oracle E-Business Suite R12.2 maintenance cycle, adop phase=fs_clone repeatedly failed while rebuilding the PATCH file system (fs2). The initial error message pointed to an edition issue, but the actual failure was buried deeper in the WebLogic configuration logs: the WebLogic Node Manager password could not be decrypted during fs2 configuration.

    After correcting the WebLogic credential configuration and re-running AutoConfig and Preclone on the RUN file system, fs_clone force=yes completed successfully.

    Context: Oracle EBS R12.2 uses WebLogic Server in the application tier. File system cloning involves WebLogic configuration and credentials when configuring the PATCH file system from the RUN file system.

    Environment

    Oracle E-Business Suite: R12.2
    Database: Oracle 19c
    Application tier: Multiple nodes
    RUN file system: fs1
    PATCH file system: fs2
    Clone method: Full file system synchronization

    RUN File System: /u01/oracle//fs1
    PATCH File System: /u01/oracle//fs2

    The Failure

    The adop phase=fs_clone operation reported:

    ERROR: Unable to set edition. Invalid edition type : PATCH

    Followed by:

    adclone.pl did not go through successfully.
    EXIT STATUS: 1

    These messages indicated failure but not the cause. The detailed WebLogic configuration logs revealed the actual exception.

    Actual Failure: WebLogic Password Decryption

    While WLST configured Node Manager credentials on fs2, the logs showed:

    File “…/txkSetAppsLibsTarget.py”, line 705, in setNodeManagerCredentials

    java.lang.AssertionError:
    java.lang.reflect.InvocationTargetException

    The stack trace continued through:

    SecurityConfigurationMBeanImpl.getNodeManagerPassword

    EncryptionServiceException:
    com.rsa.jsafe.JSAFE_PaddingException: Invalid padding

    The failure chain:

    txkSetAppsLibsTarget.py
    -> setNodeManagerCredentials()
    -> getNodeManagerPassword()
    -> WebLogic decrypt()
    -> JSAFE_PaddingException: Invalid padding

    WebLogic was unable to decrypt the Node Manager password during fs2 configuration. This pointed to a WebLogic credential/encryption configuration issue rather than a filesystem capacity or OS resource issue.

    Investigation

    Before pinpointing the WebLogic credential issue, these areas were examined:

    Filesystem Space
    The application filesystem had adequate free space. The FMW Home cloning process had progressed substantially before failing, making a simple disk-space issue unlikely.

    Port Allocation
    The clone successfully acquired all required temporary ports. No port conflicts were identified.

    Operating System
    OS logs showed no evidence of: OOM kills, Java process termination, segmentation faults, core dumps, or hs_err_pid files.

    FMW Home Cloning
    The pasteBinary operation progressed to approximately 90% before stopping. However, the actionable error was the WebLogic decryption failure:

    getNodeManagerPassword
    JSAFE_PaddingException: Invalid padding

    The 90% progress point indicated where the clone stopped, not the root cause.

    Resolution

    After reviewing the issue with a senior DBA, the WebLogic credential configuration was corrected and the RUN file system configuration was refreshed before retrying the clone.

    The following steps resolved the issue:

    1. Update boot.properties
    Update the WebLogic boot.properties file with the appropriate credentials as part of correcting the WebLogic credential configuration.

    2. Restart WebLogic
    Restart WebLogic to load the updated credential configuration.

    3. Run AutoConfig on the RUN File System
    cd $COMMON_TOP/admin/scripts
    ./adautocfg.sh

    This regenerates EBS configuration on the RUN file system.

    4. Run Preclone on the RUN File System
    cd $ADMIN_SCRIPTS_HOME
    perl adpreclone.pl appsTier

    Preclone refreshes the RUN file system configuration used for the subsequent clone operation.

    5. Rerun fs_clone in Force Mode
    adop phase=fs_clone force=yes

    The operation completed successfully.

    Result

    The PATCH file system was successfully rebuilt after the WebLogic credential configuration was corrected.

    adop phase=fs_clone force=yes -> SUCCESS

    Troubleshooting Takeaways

    Don’t Stop at Generic Errors

    Messages such as “adclone.pl did not go through successfully” or “Unable to set edition. Invalid edition type : PATCH” only indicate that the clone failed. Always examine the detailed FSCloneApplyAppsTier and WLST logs to identify the actual component failure.

    WebLogic Stack Traces Matter

    If you encounter this pattern:
    setNodeManagerCredentials
    getNodeManagerPassword
    JSAFE_PaddingException: Invalid padding

    Investigate the WebLogic credential and encryption configuration. Do not assume filesystem space, port allocation, or OS resource exhaustion is responsible.

    Look Beyond the Final FAILED Message

    The most useful error is often several layers below the final adop failure. In this case:

    SecurityConfigurationMBeanImpl.getNodeManagerPassword
    com.rsa.jsafe.JSAFE_PaddingException: Invalid padding

    This identified the WebLogic password decryption step as the failure point.

    The PATCH Edition Message Was Not the Root Cause

    The message “Unable to set edition. Invalid edition type : PATCH” appeared during the investigation but was not the cause of the fs_clone failure. The actionable failure was the WebLogic password decryption error.

    Summary

    The adop phase=fs_clone failure occurred while configuring WebLogic Node Manager credentials during PATCH file system construction. The failure occurred because WebLogic was unable to decrypt the Node Manager password during the Node Manager credential configuration step:

    java.lang.AssertionError:
    java.lang.reflect.InvocationTargetException

    SecurityConfigurationMBeanImpl.getNodeManagerPassword

    com.rsa.jsafe.JSAFE_PaddingException: Invalid padding

    The resolution involved correcting the WebLogic boot.properties configuration, restarting WebLogic, and re-running AutoConfig and Preclone on the RUN file system. A subsequent fs_clone force=yes completed successfully.

    Note: This resolution is based on remediation in a specific environment. JSAFE_PaddingException errors during EBS cloning can have different underlying causes. Always review the detailed WebLogic and WLST logs before applying this remediation to another environment.

    Disclaimer: All environment identifiers, hostnames, IP addresses, and server paths in this article have been masked with generic placeholders to protect production system information and organizational confidentiality. The technical troubleshooting methodology and error signatures remain directly applicable to similar incidents in your environment.

  • Oracle Database 19c July 2026 RU Patching – Upgrade from 19.31 to 19.32 on Linux

    الحمد لله — This post documents a real Oracle Database 19c patching activity on a Linux x86-64 environment, progressing from 19.31 to 19.32 using the July 2026 Combo Patch. The activity included precheck validation, binary patching, datapatch execution, and post-patch verification with actual command outputs.

    Introduction

    This article documents the steps followed to patch an Oracle Database 19c environment from 19.31 to 19.32 using the July 2026 Database and OJVM Release Update Combo Patch on Linux x86-64.

    The patches applied were:

    Patch 39618649
    Combo of OJVM Component Release Update 19.32.0.0.260721
    + Database Jul 2026 Release Update 19.32.0.0.260721
    
    Component patches:
    39472050 - Database Release Update 19.32.0.0.260721
    39222882 - Oracle JavaVM Component Release Update 19.32.0.0.260721

    Pre-Patching Validation

    1. Verify Current Database Patch Level

    First, verify the current patches installed in the Oracle Home:

    $ $ORACLE_HOME/OPatch/opatch lspatches

    The environment was running the following baseline before July patching:

    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

    Patching objective:

    • Database RU: 19.31 → 19.32 (39034528 → 39472050)
    • OJVM RU: 19.31 → 19.32 (38906621 → 39222882)

    6. Run DB RU Conflict Check

    Before applying the Database RU, validate for conflicting one-off patches:

    $ cd 39618649/39472050
    $ opatch prereq CheckConflictAgainstOHWithDetail -ph ./
    
    Prereq "checkConflictAgainstOHWithDetail" passed.
    
    OPatch succeeded.

    ✓ No conflicting one-off patch was identified for the DB RU 39472050.

    7. Run OJVM RU Conflict Check

    Perform the same validation for the OJVM RU:

    $ cd 39618649/39222882
    $ opatch prereq CheckConflictAgainstOHWithDetail -ph ./
    
    Prereq "checkConflictAgainstOHWithDetail" passed.
    
    OPatch succeeded.

    ✓ No conflicting one-off patch was identified for the OJVM RU 39222882.

    Post-Patching Results

    OPatch Inventory Verification

    $ $ORACLE_HOME/OPatch/opatch lspatches
    
    39222882;OJVM RELEASE UPDATE: 19.32.0.0.260721
    39472050;Database Release Update : 19.32.0.0.260721
    29585399;OCW RELEASE UPDATE 19.3.0.0.0
    
    OPatch succeeded.

    Patch progression:

    • OJVM RU: 38906621 (19.31) → 39222882 (19.32) ✓
    • Database RU: 39034528 (19.31) → 39472050 (19.32) ✓
    • OCW: 29585399 (unchanged) ✓

    Component Registry Status

    All major database components are VALID after patching:

    CATALOG         VALID
    CATEGORY        VALID
    CATJAVA         VALID
    CATOJAVA        VALID
    JAVAVM          VALID
    XML             VALID
    XDB             VALID

    Database and PDB Status

    SQL> select name, open_mode, database_role from v$database;
    
    NAME            OPEN_MODE       DATABASE_ROLE
    ----------      -----------     ----------------
    PRODDB          READ WRITE      PRIMARY
    
    SQL> show pdbs;
    
        CON_ID CON_NAME                 OPEN_MODE  RESTRICTED
    ---------- ---------------------- ---------- ----------
             2 PDB$SEED                 READ ONLY  NO
             3 APPPDB                   READ WRITE NO
             4 ARCHPDB                  READ WRITE NO

    ✓ Database and all PDBs are open and operational.

    SQL Patch Registry

    Both 19.32 patches applied successfully to CDB and APPPDB PDB:

    PATCH_ID      ACTION     STATUS          DESCRIPTION
    -----------   ---------- --------------- ----------------------------------
    39222882      APPLY      SUCCESS         OJVM RU 19.32.0.0.260721
    39472050      APPLY      SUCCESS         Database RU 19.32.0.0.260721

    Note: During the 19.32 OJVM update, the previous 19.31 OJVM patch (38906621) may be recorded as ROLLBACK SUCCESS, followed by successful application of OJVM RU 39222882. This is normal and expected during the RU transition — it is not an indication of a patching failure.

    Invalid Objects Validation

    Post-patch invalid objects count: 83 (unchanged from pre-patch baseline)

    ✓ Invalid object count matches pre-patch baseline. No new invalids introduced by 19.32 RU.

    oradism Permissions Restored

    $ ls -l $ORACLE_HOME/bin/oradism
    -rwsr-x---. 1 root oinstall 147848 May  5 12:25 /u01/app/oracle/product/19c/db_1/bin/oradism

    ✓ Permissions correctly restored to original state (root:oinstall 4750).

    Rollback Plan

    Important: Before executing any rollback, always:

    • Verify the exact version from the patch component README
    • Follow the documented rollback sequence from the README
    • Test in a non-production environment first
    • Obtain explicit approval from your database administration team or management

    If the 19.32 RU must be rolled back, the procedure generally follows this sequence (consult the specific README for patches 39472050 and 39222882 for the authoritative step-by-step guidance):

    1. Shut down the database and listener
    2. Revert the OJVM RU first, then the Database RU (reverse order of application)
    3. Start the database in restricted mode to verify compatibility
    4. Run datapatch to revert SQL patches: ./datapatch -verbose
    5. Verify patch registry and OPatch inventory reflect the reverted state
    6. Open the database normally and run post-revert health checks

    Always retain a clean, tested backup of the Oracle Home taken immediately before patching. This allows for rapid restoration if rollback becomes necessary.

    Key Takeaways

    A reliable Oracle Database RU patching activity is more than running opatch apply twice. A structured approach includes:

    • Capture existing state: Patch inventory, SQL patch registry, invalid objects, database role, PDB status, and oradism permissions before making any changes.
    • Validate prerequisites: Run conflict checks on both component patches and ensure OPatch is at the recommended version.
    • Follow the documented sequence: Binary patches in the correct order, then startup, then datapatch.
    • Verify at each step: Check OPatch inventory after binary patching, verify component registry after startup, and confirm datapatch success via the SQL registry.
    • Compare against baseline: Invalid objects, registry status, and listener configuration should match pre-patch evidence.
    • Plan for rollback: Maintain a clean backup and understand the documented rollback procedure from the official patch README before starting.

    Oracle Database 19c was successfully upgraded from the 19.31 RU level to the July 2026 19.32 RU level, including OJVM, with successful binary patching, SQL patching, and post-patch health validation.

  • Oracle EBS WebLogic: Troubleshooting Security:090220 Rule 2 Connection Rejection

    You receive a call: WebLogic requests are being rejected.

    The error appears in the logs:

    [Socket:000445]Connection rejected, filter blocked Socket,
    weblogic.security.net.FilterException:
    [Security:090220]rule 2

    At first, you might start checking WebLogic authentication, AdminServer credentials, or database connectivity.

    Don’t start there.

    The exception is already giving you a very strong clue about where to investigate.

    The Error Tells the Story

    The important part is:

    weblogic.security.net.FilterException
    [Security:090220]rule 2

    Oracle documents BEA-090220 as:

    A connection filter rule denied access.

    In other words, WebLogic is rejecting the connection because of a configured connection-filter rule.

    This is different from an authentication failure.

    The request is reaching the WebLogic server, and the connection filter is evaluating the incoming connection.

    What Is a WebLogic Connection Filter?

    WebLogic connection filters provide a network-level access-control layer.

    They can be used to control which clients are permitted to connect to a WebLogic Server instance. Oracle describes connection filters as an additional security layer that can restrict access at the network level.

    A simplified flow looks like this:

    Client
       |
       v
    WebLogic Listener
       |
       v
    Connection Filter
       |
       +---- ALLOW ----> Continue processing
       |
       +---- DENY -----> Connection rejected

    This is why an error such as:

    Connection rejected, filter blocked Socket

    is so useful during troubleshooting.

    Understanding Security:090220 Rule 2

    This is where we need to be precise.

    WebLogic evaluates connection-filter rules in the order in which they are configured.

    The first matching rule determines whether the connection is allowed or denied. If no rule matches, the connection is permitted by the default filter implementation.

    For example:

    Rule 1: 192.0.2.11 * * allow
    Rule 2: 192.0.2.12 * * allow
    Rule 3: 0.0.0.0/0 * * deny

    If a connection matches Rule 3, WebLogic reports:

    [Security:090220]rule 3

    Therefore:

    rule 2 identifies the connection-filter rule associated with the rejection reported by WebLogic. Always inspect the actual configured rule sequence rather than assuming it is the catch-all deny rule.

    Where Is the Configuration?

    For Oracle E-Business Suite Release 12.2, the WebLogic connection-filter configuration can be found in:

    $DOMAIN_HOME/config/config.xml

    Oracle’s EBS documentation shows the connection-filter configuration in this file.

    For example:

    <connection-filter>weblogic.security.net.ConnectionFilterImpl</connection-filter>
    
    <connection-filter-rule>192.0.2.11 * * allow</connection-filter-rule>
    
    <connection-filter-rule>192.0.2.12 * * allow</connection-filter-rule>
    
    <connection-filter-rule>0.0.0.0/0 * * deny</connection-filter-rule>

    In an EBS environment you may also see an EBS-specific connection-filter implementation, such as:

    <connection-filter>oracle.apps.ad.tools.configuration.wls.filter.EBSConnectionFilterImpl</connection-filter>

    If that is what your environment is using, don’t replace the filter class just because you are troubleshooting a rule. Focus on the configured rules.

    Check the Rules Before Changing Anything

    First inspect the actual configuration:

    cd $DOMAIN_HOME/config
    
    grep -n -A10 -B5 "connection-filter" config.xml

    You want to establish:

    • Which connection-filter implementation is configured?
    • What are the connection-filter rules?
    • Which source IP is making the connection?
    • Which rule is actually denying the connection?
    • Is the source IP supposed to be allowed?

    This is much better than immediately changing the filter to allow.

    Always Back Up config.xml

    Before making any manual configuration change:

    cd $DOMAIN_HOME/config
    
    cp -ip config.xml config.xml_$(date +%Y%m%d_%H%M%S).bak

    If this is an EBS environment, also consider the run/patch filesystem implications before making a change that needs to persist through online patching. Oracle’s EBS documentation notes that configuration changes on the run filesystem are propagated to the patch filesystem during fs_clone.

    Don’t Confuse This With Basic Authentication

    While reviewing config.xml, you may encounter:

    <enforce-valid-basic-auth-credentials>
        false
    </enforce-valid-basic-auth-credentials>

    It is tempting to associate this with every WebLogic security-related error.

    But BEA-090220 specifically indicates that a connection-filter rule denied access.

    Therefore, for this particular error, the first investigation should be:

    Security:090220
           ↓
    Connection Filter
           ↓
    Connection Filter Rules
           ↓
    Source IP / Port / Protocol

    rather than Basic Authentication.

    A Typical Configuration

    Oracle’s EBS documentation provides examples such as:

    <connection-filter-rule>192.0.2.11 * * allow</connection-filter-rule>
    
    <connection-filter-rule>192.0.2.12 * * allow</connection-filter-rule>
    
    <connection-filter-rule>192.0.2.100 * 17001 allow https</connection-filter-rule>
    
    <connection-filter-rule>0.0.0.0/0 * * deny</connection-filter-rule>

    The final rule:

    0.0.0.0/0 * * deny

    acts as a catch-all deny.

    Oracle specifically documents this pattern: allow the required sources first, then use 0.0.0.0/0 * * deny as the final rule so that all other sources are rejected.

    The Incident Scenario

    In our case, the error was:

    [Socket:000445]Connection rejected, filter blocked Socket,
    weblogic.security.net.FilterException:
    [Security:090220]rule 2

    During the investigation, we reviewed the WebLogic configuration and traced the rejection back to the connection-filter rules.

    The important distinction was:

    WebLogic is running
            |
            v
    Request reaches WebLogic
            |
            v
    Connection filter evaluates request
            |
            v
    Configured rule denies connection
            |
            v
    Security:090220

    That changed the direction of the investigation immediately.

    Resolution

    Once the offending rule has been identified, there are two approaches.

    Option 1 — Correct the Allow Rule

    This is the preferred approach.

    For example, if the trusted WebLogic client is:

    192.0.2.50

    the configuration could contain:

    <connection-filter-rule>192.0.2.50 * * allow</connection-filter-rule>
    
    <connection-filter-rule>0.0.0.0/0 * * deny</connection-filter-rule>

    The important point is that the allow rule must appear before the catch-all deny rule.

    Option 2 — Temporary Troubleshooting Workaround

    In a controlled troubleshooting situation, changing:

    0.0.0.0/0 * * deny

    to:

    0.0.0.0/0 * * allow

    can be used to confirm that the connection filter is the cause of the problem.

    However, this effectively removes the intended network restriction.

    So: Use this as a diagnostic/workaround step, not as the preferred permanent production configuration.

    Oracle’s documented security model is to allow the required sources and retain a final deny rule.

    If Manually Editing config.xml

    If you are manually modifying the domain configuration rather than using the WebLogic Administration Console, perform the change under your environment’s standard configuration-management procedure and ensure the Administration Server is not concurrently modifying the file.

    For a controlled manual change, the practical sequence is:

    Stop AdminServer
          |
          v
    Backup config.xml
          |
          v
    Review current connection-filter rules
          |
          v
    Make the required change
          |
          v
    Validate config.xml
          |
          v
    Start AdminServer
          |
          v
    Monitor logs
          |
          v
    Retest the connection

    Oracle also supports configuring connection filters through the WebLogic Administration Console and then activating the configuration and restarting as required.

    Troubleshooting Decision Tree

    When you encounter:

    [Socket:000445]Connection rejected, filter blocked Socket
    weblogic.security.net.FilterException
    [Security:090220]rule N

    use this approach:

                     WebLogic Request
                           |
                           v
                  WebLogic reachable?
                           |
                          YES
                           |
                           v
                 Check exact exception
                           |
                           v
              weblogic.security.net
                 FilterException?
                           |
                          YES
                           |
                           v
                  Security:090220?
                           |
                          YES
                           |
                           v
           Review connection-filter rules
                           |
                           v
              Identify rule N
                           |
                           v
            Identify source IP/port/protocol
                           |
                           v
              Does the rule allow it?
                     /          \
                   YES          NO
                    |            |
                    v            v
            Investigate next   Correct the
                 layer          filter rule

    Key Takeaways

    1. Read the exception literally — FilterException is a major clue.
    2. Security:090220 means a connection-filter rule denied access — Oracle explicitly documents BEA-090220 this way.
    3. Rule ordering matters — The first matching rule determines the result.
    4. rule 2 is not automatically the catch-all deny — Check the actual rule list before making assumptions.
    5. 0.0.0.0/0 * * deny is normally a catch-all restriction — It should generally come after the required allow rules.
    6. Don’t use a global allow as the permanent fix — If the issue is caused by a missing source IP rule, add the required source rather than permanently opening the filter.

    Final Thought

    One of the most useful troubleshooting skills in middleware administration is learning to read the error as a diagnostic path.

    Consider the original message:

    [Socket:000445]
    Connection rejected,
    filter blocked Socket,
    weblogic.security.net.FilterException:
    [Security:090220]rule 2

    Break it down:

    Connection rejected
            ↓
    Filter blocked Socket
            ↓
    WebLogic Connection Filter
            ↓
    BEA/Security 090220
            ↓
    Connection-filter rule denied access
            ↓
    Check the actual rule identified by the error

    Instead of treating it as another generic WebLogic failure, the error points us directly toward the connection-filter configuration.

    Read the error carefully. Sometimes the error message has already told you where the problem is.

Syed Anwar Ahmed – Oracle DBA Blog

Oracle Database and EBS troubleshooting guides based on real production experience.

Skip to content ↓