Skip to content
Homeβ€Ί Databaseβ€Ί SQL Developer Debugging Tutorial – Catch ORA-06512 Faster

SQL Developer Debugging Tutorial – Catch ORA-06512 Faster

Where developers are forged. Β· Structured learning Β· Free forever.
πŸ“ Part of: PL/SQL β†’ Topic 23 of 27
Step-by-step guide to using SQL Developer debugger to find the exact line causing ORA-06512.
βš™οΈ Intermediate β€” basic Database knowledge assumed
In this tutorial, you'll learn
Step-by-step guide to using SQL Developer debugger to find the exact line causing ORA-06512.
  • Exception breakpoints halt execution at the exact line that raises the error β€” eliminating manual ORA-06512 line number parsing entirely and reducing diagnosis time from 30–90 minutes to under 5 minutes
  • Both conditions must be true before debugging works: correct privilege grants AND DEBUG compilation of every procedure in the call chain β€” missing either produces silent failure with no error message
  • The Call Stack window replaces textual ORA-06512 lines with a clickable navigable view β€” click any frame to jump to that source line and inspect that scope's variables
✦ Plain-English analogy ✦ Real code with output ✦ Interview questions
⚑Quick Answer
  • SQL Developer's built-in PL/SQL debugger can trap exceptions at the exact line before ORA-06512 propagates up the call chain β€” eliminating manual stack trace parsing entirely
  • Key component 1: Exception breakpoints pause execution the moment any Oracle error is raised, before exception handlers run
  • Key component 2: The Call Stack window shows the full nested procedure chain triggering ORA-06512 as an interactive, clickable view β€” not a static text dump
  • Key component 3: The Variables window reveals the exact runtime values (NULLs, truncated strings, bad numbers) that caused the error at the moment it fired
  • Performance insight: remote debugging adds 200–500 ms latency per breakpoint hit versus local connections β€” acceptable for diagnosis, painful if you leave it on for hours
  • Production insight: developers who skip debugger setup and fall back to DBMS_OUTPUT loops waste 3–5x more time on ORA-06512 triage per incident
  • Biggest mistake: reading the error stack manually and correlating line numbers by hand instead of letting the debugger halt at the source β€” line numbers shift every time you edit the procedure, invalidating all your manual work
  • Second biggest mistake: forgetting to compile with DEBUG before starting the session β€” breakpoints are silently ignored and the debugger appears broken
🚨 START HERE
SQL Developer Debugger Quick Setup
Copy-paste ready commands for debugger configuration, privilege grants, and DEBUG compilation β€” run these before starting any debug session
🟑Need to enable debugging for a specific package or procedure
Immediate ActionGrant privileges and compile with DEBUG flag
Commands
-- Grant required privileges (run as DBA) GRANT DEBUG CONNECT SESSION TO your_developer_user; GRANT DEBUG ANY PROCEDURE TO your_developer_user; -- Alternative: grant DEBUG on specific objects only (least-privilege approach) GRANT DEBUG ON io.thecodeforge.report.generator TO your_developer_user; GRANT DEBUG ON io.thecodeforge.report.batch_runner TO your_developer_user; GRANT DEBUG ON io.thecodeforge.scheduler.nightly_job TO your_developer_user;
-- Compile procedures with DEBUG flag ALTER PROCEDURE io.thecodeforge.payment.reconcile_batch COMPILE DEBUG; ALTER PACKAGE io.thecodeforge.report.generator COMPILE DEBUG; ALTER PACKAGE io.thecodeforge.report.generator COMPILE BODY DEBUG; -- Verify DEBUG compilation status SELECT name, type, CASE WHEN debuginfo = 'YES' THEN 'DEBUG ENABLED' ELSE 'NO DEBUG INFO β€” recompile with DEBUG' END AS debug_status FROM user_procedures WHERE name IN ('RECONCILE_BATCH', 'GENERATOR', 'BATCH_RUNNER') ORDER BY name;
Fix NowOnce privileges are granted and DEBUG compilation is confirmed, set your exception breakpoint in SQL Developer's Breakpoints window and start the debug session. Do not forget to revert DEBUG compilation before promoting to production.
🟑Need to initiate a remote debug session from the target database
Immediate ActionRun DBMS_DEBUG_JDWP.CONNECT_TCP from the target session before executing the failing code
Commands
-- Run this in the TARGET database session -- This blocks until SQL Developer attaches (or timeout expires) BEGIN DBMS_DEBUG_JDWP.CONNECT_TCP( host => 'your-sqldeveloper-host.example.com', -- SQL Developer machine IP port => 4000, -- must match SQL Developer preferences timeout => 30 -- seconds to wait for attachment ); -- After SQL Developer attaches, execution continues here -- Place the failing call immediately after CONNECT_TCP io.thecodeforge.payment.reconcile_batch( p_batch_id => 12345, p_run_date => DATE '2026-04-14' ); END; /
-- In SQL Developer: Run > Debug > (select your connection) -- SQL Developer will attach to the waiting session -- Then set exception breakpoints in the Breakpoints window: -- Breakpoints window > right-click > Add Exception Breakpoint -- Error number: 1403 (for ORA-01403 NO_DATA_FOUND) -- Error number: 1 (for ORA-00001 unique constraint violated) -- Error number: 6502 (for ORA-06502 VALUE_ERROR) -- Verify the debug port is open and reachable from the DB server -- Run this from the database server OS (not SQL*Plus): -- telnet your-sqldeveloper-host.example.com 4000
Fix NowIf CONNECT_TCP times out, SQL Developer was not yet listening when the call was made. Start the SQL Developer debug listener first (Run > Debug > connection), then call CONNECT_TCP. The listener must be active before the database session initiates the connection.
🟑Need to verify which objects in a call chain are missing DEBUG compilation
Immediate ActionQuery user_procedures across the full call chain before starting the debug session
Commands
-- Check DEBUG status for all objects in a known call chain SELECT p.object_name, p.object_type, p.procedure_name, CASE WHEN p.debuginfo = 'YES' THEN 'DEBUG OK' ELSE 'NEEDS: ALTER ' || p.object_type || ' ' || p.object_name || ' COMPILE DEBUG;' END AS action_needed FROM user_procedures p WHERE p.object_name IN ( 'RECONCILE_BATCH', 'GENERATOR', 'BATCH_RUNNER', 'NIGHTLY_JOB' ) ORDER BY p.object_name, p.procedure_name;
-- Find all procedures that reference a specific object -- (useful for identifying the full call chain before debugging) SELECT DISTINCT d.name AS dependent_object, d.type AS dependent_type, d.referenced_name AS calls, d.referenced_type FROM user_dependencies d WHERE d.referenced_name = 'REPORT_TEMPLATES' AND d.referenced_type IN ('TABLE','VIEW') ORDER BY d.name; -- Then revert non-debug objects after the session -- ALTER PACKAGE io.thecodeforge.report.generator COMPILE; -- ALTER PACKAGE io.thecodeforge.report.generator COMPILE BODY;
Fix NowAny object in the call chain that shows 'NEEDS RECOMPILE' must be recompiled with DEBUG before starting the session. Breakpoints in that object will be silently ignored otherwise.
Production IncidentThree-Day ORA-06512 Diagnosis Eliminated by Debugger SetupA team spent 72 hours manually parsing ORA-06512 stacks for a nightly batch failure. After a 20-minute debugger configuration, the root cause was identified in 4 minutes on the first attempt.
SymptomNightly batch job fails at 02:34 UTC with ORA-01403 followed by three ORA-06512 lines pointing to nested procedures: io.thecodeforge.report.generator (line 142), io.thecodeforge.report.batch_runner (line 87), and io.thecodeforge.scheduler.nightly_job (line 23). The batch processes 47 report types and the error only fires for one of them. Manual stack trace analysis required identifying which of the 47 report types triggered the failure, then reading the source at the correct version, then correlating line 142 β€” which shifted every time someone edited the package for an unrelated fix. Each debugging cycle required redeployment and re-execution of the full batch, which takes 40 minutes to reach the failing report type.
AssumptionThe team believed SQL Developer was primarily a query and script tool. They had never used its PL/SQL debugger and assumed debugging PL/SQL meant using DBMS_OUTPUT.PUT_LINE to print variable values. Three engineers rotated through 72 hours of manual debugging cycles, each one adding more PUT_LINE statements and re-running the batch.
Root causeA SELECT INTO in io.thecodeforge.report.generator was returning no rows for one specific report_type value: 'QUARTERLY_ADJUSTMENT'. This report type was added to the scheduler six weeks earlier but the corresponding template record was never inserted into io.thecodeforge.report.templates. The error propagated through three nested calls. The NULL p_report_type check that should have caught this was present in the batch_runner but was only applied when p_report_type was NULL β€” not when it was an unrecognized non-NULL value. The debugger exception breakpoint would have halted at the exact SELECT INTO on the first attempt, showing p_report_type = 'QUARTERLY_ADJUSTMENT' and v_count = 0 in the Variables window. Instead, 72 hours of manual work produced the same answer.
Fix1. Configured SQL Developer remote debugging connection to the test database β€” 20 minutes total including privilege grants and firewall rule 2. Set exception breakpoint for ORA-01403 (NO_DATA_FOUND) in the Breakpoints window 3. Executed batch job through the debugger with p_run_date matching the failing night β€” execution halted at the SELECT INTO in io.thecodeforge.report.generator in 4 minutes 4. Variables window showed p_report_type = 'QUARTERLY_ADJUSTMENT' and confirmed zero rows in the templates table for that value 5. Root cause confirmed: missing template record. Inserted the missing row into io.thecodeforge.report.templates 6. Added a pre-execution validation check in batch_runner to verify all report types have corresponding template records before starting the batch run β€” fail fast with a clear error instead of propagating ORA-01403 from deep in the call chain
Key Lesson
Configure SQL Developer debugger before starting any manual stack trace parsing β€” the 20-minute setup cost is recovered on the first debugging sessionException breakpoints eliminate manual ORA-06512 line number correlation entirely β€” you do not need to know which line to break onRemote debugging works against test databases without changing application code β€” DBMS_DEBUG_JDWP.CONNECT_TCP is the only addition neededThe root cause of this incident was a missing reference data record, but the debugging method made it a 3-day investigation instead of a 4-minute oneAdd pre-execution validation at batch entry points to catch configuration errors before they propagate through nested call chains
Production Debug GuideSymptom-to-action mapping for common debugger setup and runtime issues
Debugger does not stop at breakpoints — execution runs to completion without pausing→The most common cause is missing DEBUG compilation. Run: ALTER PROCEDURE owner.proc_name COMPILE DEBUG; for each procedure in the call chain. Verify with: SELECT name, type, CASE WHEN debuginfo = 'YES' THEN 'DEBUG OK' ELSE 'MISSING DEBUG' END AS debug_status FROM user_procedures WHERE name = 'PROC_NAME'. Also check that you have DEBUG CONNECT SESSION privilege and that the Breakpoints window shows the breakpoint as active (green check), not disabled (grey).
Exception breakpoint fires but Call Stack window shows only 'anonymous block' with no procedure names→The error occurred in dynamic SQL executed via EXECUTE IMMEDIATE, in a trigger, or in a procedure compiled without DEBUG that is not visible to the debugger. For dynamic SQL: set a regular line breakpoint before the EXECUTE IMMEDIATE and check v_sql variable content. For triggers: set a breakpoint inside the trigger body, then perform the triggering DML. For procedures compiled without DEBUG: recompile the specific missing procedure with ALTER PROCEDURE proc_name COMPILE DEBUG.
Remote debugging connection refused — SQL Developer shows 'Connection refused' when trying to attach→Work through this checklist in order: (1) Confirm DBMS_DEBUG_JDWP.CONNECT_TCP was called from the target session before SQL Developer tried to attach — the call blocks and waits; (2) Verify the port number matches between the CONNECT_TCP call and SQL Developer preferences (default 4000); (3) Check firewall rules — the database server must allow outbound TCP to the SQL Developer host on the debug port; (4) Confirm the SQL Developer host IP is reachable from the database server, not just the other way around; (5) On Oracle 12c+, confirm the user has JDWP privilege: SELECT * FROM dba_sys_privs WHERE privilege LIKE '%JDWP%'.
Variables show <unreadable> or <value not available> in the watch window→The procedure was compiled without the DEBUG flag. Run ALTER PROCEDURE proc_name COMPILE DEBUG and restart the debug session. If the variable shows <unreadable> even after DEBUG compilation, it may be a package global — package globals are only visible when the Call Stack frame is within the package body. Navigate to that frame in the Call Stack window to make the variable accessible.
Debugger is extremely slow β€” each step takes 2–10 seconds instead of being near-instantβ†’Remote debugging over high-latency networks adds 200–500 ms per step under normal conditions; high-latency or lossy networks amplify this significantly. Try: (1) reduce the number of expressions in the Watch window β€” each watch expression is evaluated on every step; (2) disable automatic expression evaluation in SQL Developer preferences; (3) use Step Over instead of Step Into when possible to skip into library code you do not need to debug; (4) if the latency is consistently over 1 second, switch to a local connection or use the DBMS_OUTPUT logging approach instead.
Debug session starts but then the procedure raises ORA-01031 insufficient privileges on the first line→The DEBUG privilege is granted but the procedure owner lacks execute privilege on the objects it references, or the session user lacks DEBUG ON the specific package. Check: SELECT * FROM dba_tab_privs WHERE grantee = 'YOUR_USER' AND privilege = 'DEBUG'. Grant specifically: GRANT DEBUG ON owner.package_name TO developer_user. For owned objects, GRANT DEBUG CONNECT SESSION is sufficient — DEBUG ANY PROCEDURE is only needed for objects in other schemas.
Breakpoint fires in wrong procedure — not the one expected→Multiple compiled versions of the same procedure name exist in different schemas, and the debugger is attaching to the wrong one. Check: SELECT owner, object_name, object_type, status FROM dba_objects WHERE object_name = 'PROC_NAME' ORDER BY owner. Ensure the connection in SQL Developer uses the correct schema owner. If the procedure exists in multiple schemas, fully qualify it in your test execution block.

ORA-06512 stack traces are informative but require manual correlation work: line numbers must be matched to source code, and that source code must be at the exact version deployed when the error occurred. Any edit between error and diagnosis shifts the line numbers. SQL Developer's debugger eliminates this entire class of friction by halting execution at the exact point where an exception is raised and presenting the full call chain as a navigable, clickable interface.

The Call Stack window is the debugger's answer to ORA-06512. Each frame in the window corresponds to one ORA-06512 line in the textual stack β€” except you can click on any frame to jump directly to that line in the source and inspect every variable at that scope level. The Variables window shows exactly what values were in play at the moment the error fired. Exception breakpoints mean you do not need to know in advance which line to break on β€” you tell the debugger 'halt on ORA-01403' and it finds the line for you.

Engineers who configure exception breakpoints before starting a debugging session consistently reduce ORA-06512 diagnosis time from 30 minutes to under 5 minutes for known error codes, and from hours to under 20 minutes for unknown error codes in deep nested call chains. This guide covers the complete setup path: privilege grants, DEBUG compilation, local and remote connection configuration, exception breakpoint configuration, Call Stack navigation, variable inspection, and the production fallback pattern for environments where interactive debugging is not available.

Privileges and DEBUG Compilation Setup

Two things must be true before SQL Developer's debugger can work: the developer must have the correct Oracle privileges, and every procedure in the call chain must be compiled with the DEBUG flag. Missing either one produces silent failures β€” breakpoints are ignored without error messages, and variables show as unreadable without explanation.

Privilege requirements are straightforward: DEBUG CONNECT SESSION allows the session to initiate a debug connection; DEBUG ANY PROCEDURE allows setting breakpoints in any schema's compiled objects. For least-privilege environments, you can grant DEBUG ON specific objects instead of DEBUG ANY PROCEDURE β€” useful when developers should only debug objects they own or have been explicitly granted access to.

DEBUG compilation embeds symbol table information into the compiled object. This is what allows the debugger to map machine instructions back to source lines and variable names. Without it, the debugger cannot resolve line numbers or variable names, so breakpoints have nothing to bind to. The compilation change is permanent until you recompile without the DEBUG flag β€” which you must do before promoting to production.

The DEBUG flag slightly increases object size (10–15%) due to the embedded symbol tables, but has zero effect on runtime performance when no debugger is attached. The overhead only materializes when the debugger is actively connected and a breakpoint is hit.

debug_setup.sql Β· SQL
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
-- ===================================================
-- Step 1: Grant debugging privileges (run as DBA)
-- ===================================================

-- Option A: Full debug access (appropriate for senior developers)
GRANT DEBUG CONNECT SESSION TO your_developer_user;
GRANT DEBUG ANY PROCEDURE TO your_developer_user;

-- Option B: Least-privilege debug access (specific objects only)
GRANT DEBUG CONNECT SESSION TO your_developer_user;
GRANT DEBUG ON io.thecodeforge.report.generator TO your_developer_user;
GRANT DEBUG ON io.thecodeforge.report.batch_runner TO your_developer_user;
GRANT DEBUG ON io.thecodeforge.scheduler.nightly_job TO your_developer_user;

-- Verify privileges were granted
SELECT grantee, privilege, admin_option
FROM dba_sys_privs
WHERE grantee = 'YOUR_DEVELOPER_USER'
  AND privilege IN ('DEBUG CONNECT SESSION', 'DEBUG ANY PROCEDURE')
ORDER BY privilege;

-- ===================================================
-- Step 2: Compile target objects with DEBUG flag
-- Run for every object in the call chain
-- ===================================================

-- Compile individual procedures
ALTER PROCEDURE io.thecodeforge.payment.reconcile_batch COMPILE DEBUG;
ALTER PROCEDURE io.thecodeforge.scheduler.nightly_job COMPILE DEBUG;

-- Compile packages: spec first, then body
-- The body is where procedure code lives β€” the body must have DEBUG
ALTER PACKAGE io.thecodeforge.report.generator COMPILE DEBUG;
ALTER PACKAGE io.thecodeforge.report.generator COMPILE BODY DEBUG;

ALTER PACKAGE io.thecodeforge.report.batch_runner COMPILE DEBUG;
ALTER PACKAGE io.thecodeforge.report.batch_runner COMPILE BODY DEBUG;

-- ===================================================
-- Step 3: Verify DEBUG compilation status
-- ===================================================
SELECT p.object_name,
       p.object_type,
       p.procedure_name,
       CASE WHEN p.debuginfo = 'YES'
            THEN 'DEBUG ENABLED β€” breakpoints will work'
            ELSE 'DEBUG MISSING β€” recompile with DEBUG flag'
       END AS debug_status
FROM user_procedures p
WHERE p.object_name IN (
  'RECONCILE_BATCH',
  'GENERATOR',
  'BATCH_RUNNER',
  'NIGHTLY_JOB'
)
ORDER BY p.object_name, p.procedure_name;

-- ===================================================
-- Step 4: Revert to non-debug compilation
-- ALWAYS run this before promoting to any environment
-- beyond your local dev schema
-- ===================================================
ALTER PROCEDURE io.thecodeforge.payment.reconcile_batch COMPILE;
ALTER PACKAGE io.thecodeforge.report.generator COMPILE;
ALTER PACKAGE io.thecodeforge.report.generator COMPILE BODY;
ALTER PACKAGE io.thecodeforge.report.batch_runner COMPILE;
ALTER PACKAGE io.thecodeforge.report.batch_runner COMPILE BODY;
ALTER PROCEDURE io.thecodeforge.scheduler.nightly_job COMPILE;

-- Verify revert: all should show 'DEBUG MISSING' after revert
SELECT object_name, object_type,
       CASE WHEN debuginfo = 'YES'
            THEN 'WARNING: STILL IN DEBUG MODE β€” DO NOT DEPLOY'
            ELSE 'OK: Non-debug compilation confirmed'
       END AS deployment_status
FROM user_procedures
WHERE object_name IN (
  'RECONCILE_BATCH', 'GENERATOR', 'BATCH_RUNNER', 'NIGHTLY_JOB'
)
ORDER BY object_name;
Mental Model
DEBUG Compilation β€” What It Does and Does Not Change
DEBUG compilation is like building a program in debug mode versus release mode. The logic is identical β€” only the embedded metadata changes.
  • DEBUG adds symbol table entries to the compiled object: source line-to-bytecode mappings and variable name metadata
  • Object size increases 10–15% due to embedded symbol tables β€” negligible in practice
  • Runtime performance is identical when no debugger is attached β€” zero overhead for normal execution
  • When the debugger is attached and hits a breakpoint, it uses the symbol table to map the current bytecode position back to a source line and resolve variable names
  • DEBUG info is stored in the data dictionary (SYS.IDL_SB4$ and related tables), not in the SGA β€” it does not consume PGA or shared pool memory
  • Always revert to non-debug compilation before deploying β€” debug objects expose internal variable names in USER_PROCEDURES and the symbol table is unnecessary overhead in production
πŸ“Š Production Insight
DEBUG compilation must be reverted before production deployment β€” this is not optional.
Debug objects expose internal variable names through the data dictionary which is a security concern for procedures that handle sensitive data like PII, payment information, or credentials.
Use separate test environment schemas for all debugging sessions. If your team shares a test environment, coordinate DEBUG compilation changes to avoid confusing other developers who may be running the non-debug version.
🎯 Key Takeaway
Both conditions must be true: correct privileges AND DEBUG compilation. Missing either produces silent failures β€” no error, no breakpoints, no explanation.
Compile every procedure in the call chain with DEBUG, not just the one you think is failing.
Always revert to non-debug compilation before promoting to any shared or production environment.
Add a pre-deploy CI/CD check that fails if any procedure shows debuginfo = 'YES'.
Debug Privilege and Compilation Strategy
IfDeveloper debugging only their own schema objects
β†’
UseGRANT DEBUG CONNECT SESSION β€” sufficient for owned objects. Compile owned procedures with DEBUG. No DEBUG ANY PROCEDURE needed.
IfDeveloper debugging shared package code in another schema
β†’
UseGRANT DEBUG ON specific_package TO developer β€” least-privilege. Or GRANT DEBUG ANY PROCEDURE for unrestricted access across all schemas.
IfTeam shares a test environment and multiple developers may debug concurrently
β†’
UseCoordinate DEBUG compilation. One developer's DEBUG recompile affects all sessions using that object. Consider personal schemas for debugging.
IfCI/CD pipeline needs to verify DEBUG compilation was reverted before deploy
β†’
UseAdd a pre-deploy check: SELECT COUNT(*) FROM user_procedures WHERE debuginfo = 'YES' β€” fail the pipeline if count > 0.
IfProduction debugging is required for an unresolvable issue
β†’
UseDo NOT use SQL Developer debugger on production. Use a read-only replica or a production-mirrored test environment with the same data. Apply enhanced FORMAT_CALL_STACK logging instead.

Setting Exception Breakpoints for ORA-06512

Exception breakpoints are the highest-leverage feature in SQL Developer's debugger for ORA-06512 diagnosis. A regular line breakpoint requires you to know in advance which line to halt at. An exception breakpoint requires only that you know which error code is being raised β€” the debugger finds the line for you.

When an exception breakpoint fires, the debugger halts before the exception handler executes. This means you see the full pre-handler state: the exact line that raised the error, the values of all local variables, the state of any cursors, and the full Call Stack showing how execution reached that point. This is the state you need for diagnosis β€” not the state inside the WHEN clause after the error has already been caught.

The most common exception breakpoints for ORA-06512 investigation are ORA-01403 (NO_DATA_FOUND from SELECT INTO), ORA-00001 (unique constraint violated), ORA-06502 (VALUE_ERROR from type conversion), and ORA-01722 (invalid number from implicit conversion). If you do not know which error is causing the ORA-06512 stack, start with a general approach: set a breakpoint at the RAISE or the DML statement in the outermost procedure shown in the ORA-06512 stack, then use Step Into to drill down to the source.

exception_breakpoints.sql Β· SQL
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
-- ===================================================
-- SQL Developer Exception Breakpoint Setup
-- UI Path: View > Breakpoints > right-click > Add Exception Breakpoint
-- ===================================================

-- Common error numbers for exception breakpoints:
-- Enter these in the 'Error Number' field (without ORA- prefix):
--
--   1403  β€” ORA-01403: NO_DATA_FOUND (SELECT INTO returned no rows)
--   1     β€” ORA-00001: unique constraint violated
--   1422  β€” ORA-01422: TOO_MANY_ROWS (SELECT INTO returned multiple rows)
--   6502  β€” ORA-06502: VALUE_ERROR (type conversion failure)
--   1722  β€” ORA-01722: invalid number (implicit conversion failure)
--   2291  β€” ORA-02291: FK parent key not found
--   60    β€” ORA-00060: deadlock detected
--   1555  β€” ORA-01555: snapshot too old

-- ===================================================
-- Execution block: run this to trigger the debug session
-- The exception breakpoint will fire when the error occurs
-- ===================================================
DECLARE
  -- Declare any test variables needed
  v_batch_id  NUMBER := 12345;
  v_run_date  DATE   := DATE '2026-04-14';
BEGIN
  -- For remote debugging: connect SQL Developer first, then call CONNECT_TCP
  -- For local debugging: skip CONNECT_TCP and just call the procedure
  
  -- Call the failing procedure β€” debugger halts when exception fires
  io.thecodeforge.payment.reconcile_batch(
    p_batch_id => v_batch_id,
    p_run_date => v_run_date
  );
END;
/

-- ===================================================
-- What you see when the exception breakpoint fires:
-- ===================================================
-- 1. Execution halts at the EXACT line that raised ORA-01403
--    (e.g., line 142 in io.thecodeforge.report.generator)
-- 2. That line is highlighted in the source editor
-- 3. Variables window shows all in-scope variables:
--    p_report_type = 'QUARTERLY_ADJUSTMENT'  <-- the problem
--    p_run_date    = 2026-04-14
--    v_count       = 0                        <-- why NO_DATA_FOUND
-- 4. Call Stack window shows:
--    Frame 0: IO.THECODEFORGE.REPORT.GENERATOR.GET_TEMPLATE  line 142
--    Frame 1: IO.THECODEFORGE.REPORT.BATCH_RUNNER.RUN        line 87
--    Frame 2: IO.THECODEFORGE.SCHEDULER.NIGHTLY_JOB.EXECUTE  line 23
--
-- Click Frame 1 -> jumps to batch_runner line 87,
--   Variables window updates to show batch_runner's local variables
-- Click Frame 2 -> jumps to nightly_job line 23,
--   Variables window updates to show scheduler's local variables

-- ===================================================
-- Conditional exception breakpoint (for intermittent errors)
-- Set condition in Breakpoints > Properties > Condition:
-- ===================================================
-- Condition expression examples (enter in Breakpoints Properties dialog):
--   p_report_type = 'QUARTERLY_ADJUSTMENT'   -- only fire for this report type
--   p_batch_id > 10000                        -- only fire for large batch IDs
--   v_count = 0                               -- only fire when count is zero
--   p_customer_id IS NULL                     -- only fire for NULL customer
⚠ Exception Breakpoint Behavior β€” Critical Timing Detail
πŸ“Š Production Insight
Exception breakpoints fire before exception handlers execute β€” this is the most important behavioral detail to understand.
The pre-handler state is exactly what you need: the values that caused the error, before any recovery logic modified them.
If your exception handler logs the error and then NULLs out the offending variable as part of cleanup, you would never see the bad value in the log β€” but the debugger would show it at the breakpoint.
🎯 Key Takeaway
Exception breakpoints are the highest-leverage debugger feature for ORA-06512 β€” they find the failing line without you needing to know it in advance.
The breakpoint fires before the exception handler, giving you the pre-error variable state.
Set multiple exception breakpoints when you are uncertain which error code is being raised.
Use conditional breakpoints for intermittent errors to avoid false stops on unrelated exceptions.
Breakpoint Selection Strategy
IfORA-06512 stack shows a specific error code (e.g., ORA-01403)
β†’
UseSet exception breakpoint for that specific error number (1403). Fastest path β€” debugger finds the line automatically.
IfORA-06512 stack shows only ORA-06512 lines with no preceding error visible
β†’
UseThe preceding error was truncated. Set exception breakpoints for the most likely candidates: 1403, 1, 6502, 1722. Run and see which one fires.
IfError occurs only under specific data conditions (intermittent)
β†’
UseUse conditional exception breakpoint. Set the condition to the known triggering data value. Run the job repeatedly until the condition fires.
IfError source is in a trigger, not a procedure
β†’
UseSet a line breakpoint inside the trigger body. Perform the triggering DML. Exception breakpoints work in triggers but Call Stack may show limited trigger context.
IfError source is in dynamic SQL (EXECUTE IMMEDIATE)
β†’
UseSet a line breakpoint before the EXECUTE IMMEDIATE. Inspect v_sql variable to see the generated SQL. Dynamic SQL errors cannot be directly halted with exception breakpoints.

The Call Stack window is the debugger's visual equivalent of the ORA-06512 textual stack trace. When an exception breakpoint fires or a regular breakpoint halts execution, the Call Stack window shows every procedure frame on the current execution stack β€” the same information as the ORA-06512 lines, but interactive.

Each frame in the Call Stack corresponds to one ORA-06512 line. Frame 0 is the deepest call β€” the procedure where execution is currently halted. The final frame is the outermost caller (often the anonymous block or the application entry point). Clicking on any frame does two things simultaneously: the source editor jumps to that line, and the Variables window updates to show the local variables at that scope level. This is the key capability β€” you can inspect the state of every level of the call chain, not just the frame where the error occurred.

This eliminates the most time-consuming manual debugging step: reading ORA-06512 line numbers, finding the correct source file at the correct version, counting to the right line, and then guessing what the variable values were. The debugger shows all of this without guessing.

call_stack_navigation.sql Β· SQL
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
-- ===================================================
-- Textual ORA-06512 stack (what you see WITHOUT the debugger)
-- ===================================================
-- ORA-01403: no data found
-- ORA-06512: at "IO.THECODEFORGE.REPORT.GENERATOR", line 142
-- ORA-06512: at "IO.THECODEFORGE.REPORT.BATCH_RUNNER", line 87
-- ORA-06512: at "IO.THECODEFORGE.SCHEDULER.NIGHTLY_JOB", line 23
-- ORA-06512: at line 1
--
-- Manual work required:
-- 1. Open io.thecodeforge.report.generator source
-- 2. Navigate to line 142
-- 3. Guess what the variable values were
-- 4. Open io.thecodeforge.report.batch_runner, go to line 87
-- 5. Guess what was passed as arguments
-- 6. Repeat for nightly_job line 23
-- 7. Make a change, redeploy, re-run the batch, wait 40 minutes
-- Total: 2–4 hours per debugging cycle

-- ===================================================
-- Call Stack window (what you see WITH the debugger)
-- ===================================================
-- Frame 0: IO.THECODEFORGE.REPORT.GENERATOR.GET_TEMPLATE    line 142
--          [highlighted in source editor β€” this is where execution halted]
-- Frame 1: IO.THECODEFORGE.REPORT.BATCH_RUNNER.PROCESS_TYPE line 87
-- Frame 2: IO.THECODEFORGE.SCHEDULER.NIGHTLY_JOB.EXECUTE    line 23
-- Frame 3: anonymous block                                   line 5
--
-- Interactive actions:
-- Click Frame 0 -> source editor shows generator line 142,
--                  Variables window shows:
--                    p_report_type = 'QUARTERLY_ADJUSTMENT'
--                    p_run_date    = 2026-04-14
--                    v_template_id = <NULL>   <-- the problem
--
-- Click Frame 1 -> source editor shows batch_runner line 87,
--                  Variables window shows:
--                    v_report_types = ['MONTHLY','QUARTERLY_ADJUSTMENT','WEEKLY']
--                    v_current_type = 'QUARTERLY_ADJUSTMENT'
--                    v_batch_id     = 12345
--
-- Click Frame 2 -> source editor shows nightly_job line 23,
--                  Variables window shows:
--                    v_run_date = 2026-04-14
--                    v_job_name = 'NIGHTLY_REPORT_BATCH'
--
-- Total: 4 minutes from breakpoint fire to root cause identified
-- No redeployment, no re-execution, no guessing

-- ===================================================
-- Read the Call Stack correctly: bottom is the outermost caller
-- ===================================================
-- Frame 3 (anonymous block, line 5)    β€” the entry point (top-level caller)
--   called Frame 2 (nightly_job, line 23)
--     called Frame 1 (batch_runner, line 87)
--       called Frame 0 (generator, line 142)  β€” where the error occurred
--
-- This matches the ORA-06512 reading order:
-- The actual error is at the TOP of the ORA-06512 text stack
-- and at Frame 0 (the BOTTOM) of the Call Stack window.
-- Both read: innermost call first, outermost caller last.

-- ===================================================
-- Stepping through the call chain manually
-- (use when exception breakpoint fires at an unexpected location)
-- ===================================================
-- F7  (Step Into)  β€” enter the next called procedure
-- F8  (Step Over)  β€” execute the next line without entering sub-calls
-- F9  (Resume)     β€” continue execution until the next breakpoint
-- Shift+F7 (Step Out) β€” finish the current procedure and return to caller
--
-- Recommended ORA-06512 debugging sequence:
-- 1. Set exception breakpoint
-- 2. Run the failing code
-- 3. When breakpoint fires, inspect Frame 0 variables
-- 4. Click Frame 1 to understand the calling context
-- 5. Click Frame 2 to understand the entry conditions
-- 6. Root cause is usually apparent within 3 frames
Mental Model
Call Stack Window vs. ORA-06512 Text Stack β€” Same Data, Different Interface
The Call Stack window contains exactly the same information as the ORA-06512 textual lines β€” the only difference is that the debugger makes every frame clickable and pairs it with live variable values.
  • Each Call Stack frame maps to one ORA-06512 line β€” Frame 0 is the innermost (deepest) call, matching the first ORA-06512 line after the actual error
  • Clicking a frame navigates the source editor to that exact line at the exact version currently compiled β€” no line-number drift
  • The Variables window updates to show the scope of the clicked frame β€” you can inspect each procedure's local variables independently
  • Frame 0 is always the most valuable starting point β€” it is where the error occurred and where the offending variable value will be visible
  • The Call Stack window does not disappear after clicking through frames β€” you can navigate back to Frame 0 at any time
πŸ“Š Production Insight
The Call Stack window replaces every manual step of ORA-06512 debugging: finding the source file, navigating to the line number, and guessing at variable values.
In a nested procedure chain with 4+ levels, the manual approach takes 45–90 minutes per cycle. The debugger takes under 5 minutes per session because you skip straight to the variable values.
Train your team to click Frame 1 and Frame 2 as a reflex after every exception breakpoint β€” the root cause is often not in Frame 0 itself, but visible in the calling context at Frame 1.
🎯 Key Takeaway
The Call Stack window is the interactive equivalent of ORA-06512 text lines β€” same data, fully navigable.
Frame 0 is the innermost call and the error source. Click frames upward to understand the calling context.
The Variables window updates per-frame β€” inspect each scope independently to find where bad data entered the call chain.

Variable Inspection and Watch Expressions

The Variables and Watch windows are where debugging converts from 'I know where it failed' to 'I know why it failed.' After the Call Stack window shows you which line raised the error, the Variables window shows you what values were in play at that moment β€” the exact data state that caused the exception.

For ORA-06512 debugging, variable inspection targets the inputs to the failing operation. For a SELECT INTO that raised ORA-01403, inspect the WHERE clause parameters β€” one of them is likely NULL, the wrong value, or mismatched in type. For an ORA-06502 VALUE_ERROR on a string assignment, inspect the source string's length against the target variable's declared size. For ORA-01722, inspect the string being passed to TO_NUMBER β€” it contains a character that is not numeric.

The Watch window allows custom expressions that the Variables window does not show by default: SQLCODE, SQLERRM, cursor attributes like v_cursor%ROWCOUNT, and collection properties like v_collection.COUNT. These expressions are evaluated on every step, so keep the Watch window lean β€” too many expressions slow down remote debugging sessions.

When the Variables window cannot show a value (package globals are only visible when you are in that package's frame), use the Watch window with a fully qualified expression: io.thecodeforge.config_pkg.v_current_env evaluates the package global directly.

variable_inspection.sql Β· SQL
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
-- ===================================================
-- Watch window expressions for ORA-06512 debugging
-- Add these via: Watch window > right-click > Add Watch
-- ===================================================

-- Universal: current error state
SQLCODE
SQLERRM

-- ORA-01403 (NO_DATA_FOUND): inspect SELECT INTO parameters
p_report_type               -- is this NULL or an unrecognized value?
p_customer_id               -- is this NULL?
v_count                     -- is this 0 when it should be > 0?

-- ORA-01422 (TOO_MANY_ROWS): confirm uniqueness assumption
v_customer_count            -- this should be 1, might be > 1

-- ORA-06502 (VALUE_ERROR): length and type checks
LENGTH(v_string_var)        -- is this longer than the target VARCHAR2?
DUMP(v_string_var)          -- raw bytes β€” reveals encoding issues
LENGTH(v_description)       -- compare against column definition length

-- ORA-01722 (invalid number): check string content
v_amount_str                -- does this contain '$', ',', or spaces?
REGEXP_REPLACE(v_amount_str, '[^0-9.\-]', '')  -- stripped version

-- ORA-00001 (unique constraint): see the duplicate key values
p_order_id                  -- what value is being inserted as PK?
p_batch_id || '_' || p_seq  -- composite key components

-- Cursor state inspection
v_cursor%ROWCOUNT           -- how many rows fetched so far?
v_cursor%ISOPEN             -- is the cursor still open?
v_collection.COUNT          -- number of elements in collection
v_collection.FIRST          -- first index (NULL if empty)
v_collection.LAST           -- last index

-- Conditional expressions for context
CASE WHEN p_report_type IS NULL THEN 'NULL_INPUT' ELSE p_report_type END
CASE WHEN v_count = 0 THEN 'NO_TEMPLATE_FOUND' ELSE TO_CHAR(v_count) || '_FOUND' END

-- ===================================================
-- Programmatic variable logging for post-mortem analysis
-- Use this pattern when SQL Developer debugger is unavailable
-- (automated batch jobs, production debugging)
-- ===================================================
CREATE OR REPLACE PROCEDURE io.thecodeforge.debug.log_variables(
  p_procedure_name IN VARCHAR2,
  p_context        IN CLOB
) IS
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  INSERT INTO io.thecodeforge.debug.variable_snapshot (
    snapshot_id,
    procedure_name,
    context_dump,
    call_stack,
    session_id,
    db_user,
    created_at
  ) VALUES (
    io.thecodeforge.debug.snapshot_seq.NEXTVAL,
    p_procedure_name,
    p_context,
    DBMS_UTILITY.FORMAT_CALL_STACK,  -- capture the full stack at log time
    SYS_CONTEXT('USERENV', 'SESSIONID'),
    SYS_CONTEXT('USERENV', 'SESSION_USER'),
    SYSTIMESTAMP
  );
  COMMIT;
END log_variables;
/

-- Usage: add before a suspect SELECT INTO to capture pre-failure state
CREATE OR REPLACE PROCEDURE io.thecodeforge.report.generator(
  p_report_type IN VARCHAR2,
  p_run_date    IN DATE
) IS
  v_template_id NUMBER;
  v_count       NUMBER;
BEGIN
  -- Capture state before the suspect operation
  -- Remove this after debugging β€” it adds an autonomous transaction per call
  io.thecodeforge.debug.log_variables(
    p_procedure_name => 'GENERATOR.GET_TEMPLATE',
    p_context        =>
      'p_report_type=' || NVL(p_report_type, 'NULL') ||
      ', p_run_date=' || TO_CHAR(p_run_date, 'YYYY-MM-DD') ||
      ', session=' || SYS_CONTEXT('USERENV', 'SESSIONID')
  );
  
  -- The suspect SELECT INTO
  SELECT template_id INTO v_template_id
  FROM io.thecodeforge.report.templates
  WHERE report_type = p_report_type    -- p_report_type = 'QUARTERLY_ADJUSTMENT'
    AND effective_date <= p_run_date   -- and this date comparison
    AND active_flag = 'Y';
  
  -- ... rest of procedure ...
  NULL;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RAISE_APPLICATION_ERROR(-20103,
      'No active template found for report type: ' ||
      NVL(p_report_type, 'NULL') ||
      ' as of ' || TO_CHAR(p_run_date, 'YYYY-MM-DD'));
END generator;
/
πŸ”₯Variable Inspection β€” What to Look For by Error Code
  • ORA-01403 (NO_DATA_FOUND): inspect every WHERE clause parameter β€” look for NULL values, type mismatches, or values that do not exist in the referenced table
  • ORA-01422 (TOO_MANY_ROWS): inspect the WHERE clause β€” a uniqueness assumption is violated; check what makes the query return multiple rows
  • ORA-06502 (VALUE_ERROR): use LENGTH() on the source and compare against the target variable's declared size; use DUMP() to reveal encoding issues and non-printable characters
  • ORA-01722 (invalid number): inspect the string being converted β€” look for currency symbols ($, Β£), commas, spaces, or leading/trailing whitespace
  • ORA-00001 (unique constraint violated): inspect the values being inserted for the constrained columns β€” the duplicate key is one of those values
  • ORA-02291 (FK parent not found): inspect the foreign key column value β€” either it is NULL (NOT NULL constraint might be missing) or the parent record does not exist
πŸ“Š Production Insight
The Variables window shows what values were in play at the moment the error fired β€” this is the single most valuable piece of information for diagnosis.
Add SQLCODE and SQLERRM to the Watch window before starting any debug session β€” they show the current error state in real time as you step through the code.
Use DUMP() for conversion errors: it shows the raw byte content of a VARCHAR2 variable, revealing non-printable characters, unexpected encoding, or invisible trailing spaces that cause ORA-06502 and ORA-01722.
🎯 Key Takeaway
The Variables window shows the exact runtime values that caused the error β€” this converts 'where it failed' into 'why it failed.'
Add SQLCODE, SQLERRM, and parameter values to the Watch window before starting every debug session.
Use DUMP() for conversion errors β€” invisible characters and encoding issues are only visible at the byte level.

Remote Debugging for Test and Staging Environments

Remote debugging connects SQL Developer running on your workstation to a PL/SQL session running on a different database host. This is the correct approach for errors that only reproduce in test or staging environments β€” which is most of them, since local developer schemas rarely have production-volume data or the exact configuration that triggers the error.

The architecture is slightly counterintuitive: the database session initiates the connection outbound to SQL Developer, not the other way around. DBMS_DEBUG_JDWP.CONNECT_TCP is called from inside the database session, pointing at the SQL Developer host and port. SQL Developer listens on that port and attaches when the call is received. Once attached, both sides communicate over the JDWP (Java Debug Wire Protocol) connection β€” the same protocol used by Java debuggers.

The firewall implications follow from this architecture: the database server must be able to reach the SQL Developer host on the debug port (default 4000) via outbound TCP. Many corporate environments allow outbound TCP from database servers by default but restrict inbound β€” which makes this configuration firewall-friendly compared to alternatives where the debugger initiates the connection.

Remote debugging adds 200–500 ms latency per breakpoint interaction under normal network conditions. This is acceptable for diagnosis but becomes painful for step-by-step execution. Use Step Over (F8) rather than Step Into (F7) whenever possible to skip library code you do not need to inspect, and keep the Watch window expression count minimal to reduce per-step evaluation overhead.

remote_debugging.sql Β· SQL
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
-- ===================================================
-- Remote debugging setup: overview of the connection flow
-- ===================================================
--
-- 1. SQL Developer (your workstation) starts listening on port 4000
--    Menu: Run > Remote Debug... > enter listening port > OK
--    SQL Developer is now waiting for an inbound JDWP connection
--
-- 2. Target database session calls CONNECT_TCP pointing at SQL Developer
--    The call BLOCKS until SQL Developer attaches or timeout expires
--
-- 3. SQL Developer attaches to the waiting session
--    The blocked CONNECT_TCP call returns, execution continues
--
-- 4. The failing procedure is called β€” exception breakpoints and line
--    breakpoints now work as in local debugging
--
-- Network requirement:
--   Database server ---outbound TCP 4000---> SQL Developer workstation
--   (database server initiates; SQL Developer listens)

-- ===================================================
-- Step 1: In SQL Developer, start the remote debug listener
-- Run > Remote Debug > Listening Port: 4000 > OK
-- Status bar shows: "Waiting for remote debug connection..."
-- ===================================================

-- ===================================================
-- Step 2: In the TARGET database session, run this block
-- Replace the host with your SQL Developer machine IP or hostname
-- ===================================================
DECLARE
  v_batch_id NUMBER := 12345;
  v_run_date DATE   := DATE '2026-04-14';
BEGIN
  -- Initiate debug connection from database to SQL Developer
  -- This BLOCKS until SQL Developer attaches (or timeout expires)
  DBMS_DEBUG_JDWP.CONNECT_TCP(
    host    => '10.0.1.45',   -- SQL Developer host IP or hostname
    port    => 4000,           -- must match SQL Developer listening port
    timeout => 60              -- seconds to wait before giving up
  );
  
  -- CONNECT_TCP returned β€” SQL Developer is now attached
  -- Breakpoints are now active. Call the failing procedure:
  io.thecodeforge.payment.reconcile_batch(
    p_batch_id => v_batch_id,
    p_run_date => v_run_date
  );
  
  -- Optionally disconnect after debugging is complete
  -- DBMS_DEBUG_JDWP.DISCONNECT;
END;
/

-- ===================================================
-- Verify JDWP privilege (required on Oracle 12c+)
-- ===================================================
SELECT grantee, privilege
FROM dba_sys_privs
WHERE grantee = 'YOUR_USER'
  AND privilege LIKE '%JDWP%';

-- Grant if missing (run as DBA)
GRANT JDWP TO your_developer_user;

-- ===================================================
-- Troubleshooting: test port reachability from DB server
-- (run from OS on the database server, not from SQL*Plus)
-- ===================================================
-- Linux/Unix:
--   nc -zv your-sqldeveloper-host.example.com 4000
--   telnet your-sqldeveloper-host.example.com 4000
--
-- Windows (PowerShell):
--   Test-NetConnection -ComputerName your-sqldeveloper-host -Port 4000

-- ===================================================
-- Defensive wrapper: attempt debug attach, fall back gracefully
-- Useful in test automation where debugger attachment is optional
-- ===================================================
CREATE OR REPLACE PROCEDURE io.thecodeforge.debug.try_attach(
  p_debug_host IN VARCHAR2 DEFAULT 'localhost',
  p_debug_port IN NUMBER   DEFAULT 4000,
  p_timeout    IN NUMBER   DEFAULT 15
) IS
BEGIN
  DBMS_DEBUG_JDWP.CONNECT_TCP(
    host    => p_debug_host,
    port    => p_debug_port,
    timeout => p_timeout
  );
  DBMS_OUTPUT.PUT_LINE(
    'Debug session attached: ' || p_debug_host || ':' || p_debug_port
  );
EXCEPTION
  WHEN OTHERS THEN
    -- Timeout or connection refused β€” continue without debugger
    DBMS_OUTPUT.PUT_LINE(
      'Debug attach failed (' || SQLERRM || ') β€” running without debugger'
    );
END try_attach;
/
⚠ Remote Debugging β€” Operational Rules
πŸ“Š Production Insight
Remote debugging is the right tool for environment-specific errors β€” the ones that occur in staging but not locally because staging has production-schema data volume or specific configuration.
The 200–500 ms per-step overhead is real but manageable. For most ORA-06512 debugging sessions, you need 10–20 steps at most. That is 5–10 seconds of overhead, not hours.
If the latency is consistently over 1 second per step, the network path between the database server and your workstation has a problem that needs to be addressed separately from the debugging session.
🎯 Key Takeaway
Remote debugging connects SQL Developer to a database session on a different host β€” the database initiates the outbound TCP connection, not SQL Developer.
Pre-configure firewall rules before your next incident β€” discovering the debug port is blocked during a 3 AM incident adds frustration without adding diagnostic value.
Never use remote debugging on production databases β€” use enhanced FORMAT_CALL_STACK logging instead.
Debugging Environment Selection
IfError is reproducible locally with test data in your dev schema
β†’
UseUse local SQL Developer connection β€” no CONNECT_TCP needed, fastest iteration, zero network latency
IfError occurs only in test or staging β€” requires staging data volume or configuration
β†’
UseUse remote debugging with DBMS_DEBUG_JDWP.CONNECT_TCP. Configure the firewall rule in advance β€” do not wait until the incident to discover the port is blocked.
IfError is intermittent and cannot be reproduced on demand
β†’
UseSet exception breakpoints, leave the debug session running, and execute the batch or workload repeatedly until the breakpoint fires. Remote sessions can remain open for hours.
IfError occurs in a long-running batch job that takes 40+ minutes to reach the failing code
β†’
UseSet a conditional exception breakpoint to filter for the specific data condition that triggers the failure. This avoids stepping through thousands of successful iterations.
IfError occurs in production only and cannot be reproduced in staging
β†’
UseDo not use the debugger. Use enhanced error logging with FORMAT_CALL_STACK, FORMAT_ERROR_BACKTRACE, and parameter capture. Reproduce in staging using logged parameters.

Automated Stack Capture Without the Debugger

Interactive debugging is not always available. Production environments should never have SQL Developer attached β€” the performance impact, security exposure of DEBUG compilation, and operational risk are not justified for production debugging. Scheduled batch jobs run unattended without a developer waiting to attach a debug session. And intermittent errors that require hours of waiting for conditions to align are impractical to debug interactively.

For all of these scenarios, the fallback is programmatic stack capture using DBMS_UTILITY.FORMAT_CALL_STACK and DBMS_UTILITY.FORMAT_ERROR_STACK. These two functions together capture the same information as the debugger's Call Stack and error display β€” the call chain leading to the error, the exact error code and message, and the ORA-06512 frame lines. Capturing them in an AUTONOMOUS_TRANSACTION ensures the log record survives even when the main transaction rolls back due to the error.

The critical addition over basic ORA-06512 logging is the parameter capture: log the input values that were active at the time of the error alongside the stack. A stack trace without parameters tells you where the error occurred. Parameters tell you why β€” and enable exact reproduction in a test environment where you can attach the debugger.

automated_stack_capture.sql Β· SQL
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
-- ===================================================
-- Error log table: production stack capture schema
-- ===================================================
CREATE TABLE io.thecodeforge.logging.error_log (
  error_id        NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  module_name     VARCHAR2(128)  NOT NULL,
  error_code      NUMBER,
  error_message   CLOB,
  call_stack      CLOB,   -- DBMS_UTILITY.FORMAT_CALL_STACK
  error_stack     CLOB,   -- DBMS_UTILITY.FORMAT_ERROR_STACK
  error_backtrace CLOB,   -- DBMS_UTILITY.FORMAT_ERROR_BACKTRACE
  parameters      CLOB,   -- input values at time of error
  session_id      NUMBER,
  os_user         VARCHAR2(128),
  db_user         VARCHAR2(128),
  client_info     VARCHAR2(64),
  module_ctx      VARCHAR2(64),
  action_ctx      VARCHAR2(64),
  created_at      TIMESTAMP DEFAULT SYSTIMESTAMP
);

-- Index for common query patterns
CREATE INDEX io.thecodeforge.logging.err_log_code_ts_idx
  ON io.thecodeforge.logging.error_log (error_code, created_at DESC);

CREATE INDEX io.thecodeforge.logging.err_log_module_ts_idx
  ON io.thecodeforge.logging.error_log (module_name, created_at DESC);

-- ===================================================
-- Centralized error capture procedure
-- Call this from EVERY exception handler before re-raising
-- ===================================================
CREATE OR REPLACE PROCEDURE io.thecodeforge.logging.capture_error(
  p_module     IN VARCHAR2,
  p_parameters IN CLOB DEFAULT NULL
) IS
  PRAGMA AUTONOMOUS_TRANSACTION;  -- survives main transaction rollback
BEGIN
  INSERT INTO io.thecodeforge.logging.error_log (
    module_name,
    error_code,
    error_message,
    call_stack,
    error_stack,
    error_backtrace,
    parameters,
    session_id,
    os_user,
    db_user,
    client_info,
    module_ctx,
    action_ctx,
    created_at
  ) VALUES (
    p_module,
    SQLCODE,
    SQLERRM,
    DBMS_UTILITY.FORMAT_CALL_STACK,      -- who called whom at error time
    DBMS_UTILITY.FORMAT_ERROR_STACK,     -- ORA codes and messages (up to 2000 bytes)
    DBMS_UTILITY.FORMAT_ERROR_BACKTRACE, -- original line numbers preserved through re-raises
    p_parameters,
    SYS_CONTEXT('USERENV', 'SESSIONID'),
    SYS_CONTEXT('USERENV', 'OS_USER'),
    SYS_CONTEXT('USERENV', 'SESSION_USER'),
    SYS_CONTEXT('USERENV', 'CLIENT_INFO'),
    SYS_CONTEXT('USERENV', 'MODULE'),
    SYS_CONTEXT('USERENV', 'ACTION'),
    SYSTIMESTAMP
  );
  COMMIT;  -- autonomous transaction commit β€” does not affect caller's transaction
EXCEPTION
  WHEN OTHERS THEN
    -- If error logging itself fails, write to alert log and continue
    -- Never let logging failure suppress the original error
    SYS.DBMS_SYSTEM.KSDWRT(
      2,  -- alert log destination
      'ERROR LOG FAILED in capture_error for module=' || p_module ||
      ' SQLCODE=' || SQLCODE
    );
END capture_error;
/

-- ===================================================
-- Usage pattern: every production exception handler
-- ===================================================
CREATE OR REPLACE PROCEDURE io.thecodeforge.payment.reconcile_batch(
  p_batch_id IN NUMBER,
  p_run_date IN DATE
) IS
  v_processed NUMBER := 0;
  v_failed    NUMBER := 0;
BEGIN
  -- Business logic
  FOR rec IN (
    SELECT * FROM io.thecodeforge.payment.pending_transactions
    WHERE batch_id = p_batch_id
  ) LOOP
    BEGIN
      io.thecodeforge.payment.process_transaction(
        p_txn_id    => rec.transaction_id,
        p_batch_id  => p_batch_id
      );
      v_processed := v_processed + 1;
    EXCEPTION
      WHEN OTHERS THEN
        -- Capture: stack + parameters + context
        io.thecodeforge.logging.capture_error(
          p_module     => 'RECONCILE_BATCH.LOOP',
          p_parameters =>
            'batch_id='     || p_batch_id        || CHR(10) ||
            'run_date='     || TO_CHAR(p_run_date, 'YYYY-MM-DD') || CHR(10) ||
            'txn_id='       || rec.transaction_id || CHR(10) ||
            'processed_so_far=' || v_processed
        );
        v_failed := v_failed + 1;
        -- For batch processing: log-and-continue pattern
        -- Do NOT re-raise here β€” allows batch to process remaining records
    END;
  END LOOP;
  
  -- Report completion with counts
  io.thecodeforge.logging.capture_error(
    p_module     => 'RECONCILE_BATCH.SUMMARY',
    p_parameters =>
      'batch_id='  || p_batch_id  || CHR(10) ||
      'processed=' || v_processed || CHR(10) ||
      'failed='    || v_failed
  );
  
  COMMIT;
END reconcile_batch;
/

-- ===================================================
-- Post-mortem query: find the failing call chain
-- Run this after a production error to reconstruct the stack
-- ===================================================
SELECT
  el.error_id,
  el.module_name,
  el.error_code,
  el.error_message,
  el.parameters,
  el.call_stack,
  el.error_backtrace,
  el.db_user,
  el.os_user,
  el.created_at
FROM io.thecodeforge.logging.error_log el
WHERE el.created_at > SYSTIMESTAMP - INTERVAL '1' HOUR
  AND el.error_code != 0   -- exclude informational entries
ORDER BY el.created_at DESC
FETCH FIRST 20 ROWS ONLY;
πŸ’‘Production Stack Capture β€” Three Functions, One Complete Picture
  • FORMAT_CALL_STACK: shows the procedure call chain at the moment capture_error was called β€” equivalent to the debugger's Call Stack window
  • FORMAT_ERROR_STACK: shows the ORA error codes and messages including ORA-06512 lines β€” up to 2000 bytes (use when SQLERRM's 512-byte limit truncates deep stacks)
  • FORMAT_ERROR_BACKTRACE: shows the original line number where the error was first raised, preserved through re-raises β€” this is the one that gives you the exact line even when multiple RAISE statements are in the propagation path
  • Log all three, always β€” each provides information the others do not
  • AUTONOMOUS_TRANSACTION is non-negotiable for error logging β€” without it, the ROLLBACK triggered by the error deletes your log record
  • Log input parameters in a structured format (key=value separated by CHR(10)) so you can parse them programmatically and reproduce the exact failure condition in a test environment
πŸ“Š Production Insight
FORMAT_CALL_STACK and FORMAT_ERROR_STACK together give you everything the debugger's Call Stack window shows β€” the same call chain, the same error codes, the same line numbers. The difference is that you see it after the fact instead of interactively.
AUTONOMOUS_TRANSACTION is the most important implementation detail in capture_error. Without it, the INSERT to error_log is part of the main transaction, and when the error causes a ROLLBACK, your log record disappears with it. This produces the nightmare scenario: an error occurs, your handler logs it, the transaction rolls back, and the log is empty β€” no trace that the error ever happened.
Parameter logging enables exact failure reproduction. A stack trace without parameters tells you which SELECT INTO failed. Parameters tell you which customer_id, which report_type, which batch_id caused it β€” and those values let you reproduce it in a test environment where you can attach the debugger.
🎯 Key Takeaway
For production: use FORMAT_CALL_STACK + FORMAT_ERROR_STACK + FORMAT_ERROR_BACKTRACE in an AUTONOMOUS_TRANSACTION logging procedure.
Log all three functions β€” each captures information the others do not.
Always include input parameter values in the log β€” a stack without parameters cannot be reproduced for test environment debugging.
AUTONOMOUS_TRANSACTION is non-negotiable β€” without it, ROLLBACK erases your error log.
πŸ—‚ Debugging Approaches for ORA-06512
Trade-offs between debugging methods β€” choose based on environment, error reproducibility, and time available
ApproachTime to DiagnosisEnvironmentContext QualityBest For
Manual ORA-06512 text parsingSlow (30–90 min per cycle)AnyLow β€” line numbers only; line numbers shift with code changesSingle-procedure scripts with no nested calls; debugging on a machine where SQL Developer is unavailable
DBMS_OUTPUT.PUT_LINE loggingSlow (15–30 min per cycle)Any with output enabledLow to Medium β€” only what you remembered to log; requires redeploy per iterationLegacy codebases without a modern error log table; quick smoke-check of a known variable value
SQL Developer local debuggerFast (2–5 min first attempt)Local dev schemaHighest β€” full interactive variable state, navigable Call Stack, Watch expressionsDevelopment environment; errors reproducible with local test data; any new ORA-06512 investigation
SQL Developer remote debuggerMedium (5–15 min setup + 2–5 min diagnosis)Test/StagingHighest β€” identical to local, with 200–500 ms per-step overheadEnvironment-specific errors that require staging data volume or configuration
Exception breakpoints (any connection)Fastest (under 3 min from breakpoint set to root cause)Local or RemoteHighest β€” halts at the exact raising line with full pre-handler variable stateKnown error code investigation; eliminating manual line-number correlation entirely
FORMAT_CALL_STACK + error log tableFast (post-mortem, under 5 min to read the log)Production or any automated jobMedium β€” stack text and parameters but no interactive variable inspectionProduction errors; unattended batch jobs; intermittent errors captured on first occurrence
Conditional breakpointsMedium setup, then fastest (fires only on matching data)Local or RemoteHighest β€” full interactive state, filtered to the specific data conditionIntermittent errors tied to specific parameter values; batch jobs with millions of successful iterations before the error

🎯 Key Takeaways

  • Exception breakpoints halt execution at the exact line that raises the error β€” eliminating manual ORA-06512 line number parsing entirely and reducing diagnosis time from 30–90 minutes to under 5 minutes
  • Both conditions must be true before debugging works: correct privilege grants AND DEBUG compilation of every procedure in the call chain β€” missing either produces silent failure with no error message
  • The Call Stack window replaces textual ORA-06512 lines with a clickable navigable view β€” click any frame to jump to that source line and inspect that scope's variables
  • Remote debugging architecture: the database session initiates outbound TCP to SQL Developer, not the reverse β€” SQL Developer must be listening before DBMS_DEBUG_JDWP.CONNECT_TCP is called
  • In production, use FORMAT_CALL_STACK + FORMAT_ERROR_STACK + FORMAT_ERROR_BACKTRACE in an AUTONOMOUS_TRANSACTION logging procedure β€” log input parameters alongside the stack to enable exact failure reproduction in a test environment
  • Always revert DEBUG compilation before promoting to production β€” add a CI/CD gate that checks debuginfo = 'YES' and fails the pipeline if any production-bound object is still in debug mode

⚠ Common Mistakes to Avoid

    βœ•Not compiling procedures with the DEBUG flag before starting a debug session
    Symptom

    Breakpoints are silently ignored β€” execution runs to completion without pausing. Variables show as <unreadable> in the Watch window. The debugger appears to be broken or misconfigured, leading developers to abandon it.

    Fix

    Run ALTER PROCEDURE owner.proc_name COMPILE DEBUG before starting the session. For packages, compile both spec and body: ALTER PACKAGE owner.pkg_name COMPILE DEBUG; ALTER PACKAGE owner.pkg_name COMPILE BODY DEBUG. Verify with: SELECT name, type, CASE WHEN debuginfo = 'YES' THEN 'OK' ELSE 'MISSING' END FROM user_procedures WHERE name = 'YOUR_PROC'. Repeat for every procedure in the call chain β€” a single non-debug procedure in the middle of the chain breaks the debugger's view of that frame.

    βœ•Reading ORA-06512 stack traces manually instead of using exception breakpoints
    Symptom

    Engineers spend 30–90 minutes correlating line numbers with source code. Each code change shifts line numbers, invalidating the correlation and requiring re-analysis. Multiple debugging cycles are needed because manual guesses at variable values are wrong. The team treats the debugger as a 'nice to have' rather than a primary diagnostic tool.

    Fix

    Set an exception breakpoint for the error code shown in the ORA-06512 stack before doing any manual analysis. The 5-minute setup investment (privilege grants + DEBUG compilation + exception breakpoint) is always recovered on the first debugging session. Use the Call Stack window to navigate the procedure chain interactively. The manual approach is always slower for nested procedure chains with three or more levels.

    βœ•Leaving DEBUG compilation enabled on objects that get promoted to production
    Symptom

    Production objects contain debug symbol information visible in USER_PROCEDURES. Object sizes are 10–15% larger than necessary. Internal variable names, loop counter names, and parameter names are exposed in the data dictionary β€” a security concern for procedures handling PII, credentials, or business-sensitive logic. If someone accidentally attaches a debug session to production, breakpoints would work.

    Fix

    Revert to non-debug compilation before promoting: ALTER PROCEDURE proc_name COMPILE; ALTER PACKAGE pkg_name COMPILE; ALTER PACKAGE pkg_name COMPILE BODY. Add a pre-deploy CI/CD gate: SELECT COUNT(*) FROM user_procedures WHERE debuginfo = 'YES' β€” if this returns any rows, fail the pipeline. Keep debug compilation strictly within developer-owned local schemas.

    βœ•Using remote debugging over a high-latency network without adjusting expectations or technique
    Symptom

    Each step takes 2–10 seconds instead of being near-instant. Developers conclude the debugger is broken or unusable and abandon it. They return to DBMS_OUTPUT.PUT_LINE loops, which take longer but feel more familiar.

    Fix

    Accept 200–500 ms per step as normal for remote connections. Reduce Watch window expressions to the minimum needed β€” each expression is evaluated on every step. Use Step Over (F8) to skip library calls you do not need to inspect. Use exception breakpoints to jump directly to the error location instead of stepping through hundreds of lines. If latency consistently exceeds 1 second, investigate the network path separately.

    βœ•Not logging input parameters alongside error stacks in production
    Symptom

    Production error log shows the full FORMAT_CALL_STACK and FORMAT_ERROR_STACK β€” the call chain is clear. But there are no parameter values. Engineers cannot reproduce the failure in a test environment because they do not know which batch_id, customer_id, or report_type caused it. The incident remains unresolved until the same error recurs and a developer catches it with DBMS_OUTPUT.

    Fix

    Always pass p_parameters to capture_error with all input values serialized: 'batch_id=' || p_batch_id || CHR(10) || 'run_date=' || TO_CHAR(p_run_date, 'YYYY-MM-DD'). These values enable exact failure reproduction in a test environment where you can attach the SQL Developer debugger. Without parameters, the stack trace is interesting but not actionable.

    βœ•Starting a remote debug session without verifying firewall rules in advance
    Symptom

    DBMS_DEBUG_JDWP.CONNECT_TCP times out after 30–60 seconds. SQL Developer never shows an attachment. The debugging session cannot start. During a production incident, this wastes 30–60 minutes confirming the network path is blocked before switching to the logging fallback.

    Fix

    Test port reachability before you need to debug in anger: from the database server OS, run: nc -zv your-sqldeveloper-host.example.com 4000 (Linux) or Test-NetConnection -ComputerName your-sqldeveloper-host -Port 4000 (PowerShell). Do this test during normal working hours, not during a 3 AM incident. Document the result and open firewall rules proactively in test environments.

Interview Questions on This Topic

  • QHow would you set up SQL Developer to debug an ORA-01403 error that occurs at line 142 in a three-level nested procedure call chain?SeniorReveal
    Start by compiling all three procedures in the call chain with DEBUG: ALTER PROCEDURE proc_name COMPILE DEBUG for standalone procedures, ALTER PACKAGE pkg_name COMPILE BODY DEBUG for package procedures. Verify with SELECT name, debuginfo FROM user_procedures WHERE name IN (...). Grant DEBUG CONNECT SESSION and DEBUG ANY PROCEDURE to the developer account if not already granted. In SQL Developer, open the Breakpoints window and add an exception breakpoint for error number 1403. Execute the failing call through the debugger β€” either locally or via DBMS_DEBUG_JDWP.CONNECT_TCP for remote. When the exception fires, the debugger halts at the exact SELECT INTO at line 142. Inspect the Variables window: the NULL parameter or the unrecognized value that caused the empty result set will be immediately visible. Click Frame 1 in the Call Stack window to see what the caller passed. Root cause is typically identified in under 5 minutes.
  • QWhat is the difference between DBMS_UTILITY.FORMAT_CALL_STACK, FORMAT_ERROR_STACK, and FORMAT_ERROR_BACKTRACE, and when would you log each one?Mid-levelReveal
    They capture three different views of the same error event. FORMAT_CALL_STACK returns the current procedure call chain at the moment the function is called β€” it shows who called whom and at which line, equivalent to the debugger's Call Stack window. FORMAT_ERROR_STACK returns the ORA error codes and messages including all ORA-06512 lines β€” it is the textual error stack up to 2000 bytes, longer than SQLERRM's 512-byte limit. FORMAT_ERROR_BACKTRACE returns the original line number where the exception was first raised, preserved through RAISE statements β€” this is the one that does not shift when you re-raise an exception through multiple handlers. The best practice is to log all three: FORMAT_CALL_STACK for the call chain, FORMAT_ERROR_STACK for the error codes, FORMAT_ERROR_BACKTRACE for the original line number. They are complementary, not redundant.
  • QHow would you debug an ORA-06512 error in production where you cannot attach SQL Developer's interactive debugger?Mid-levelReveal
    Implement centralized error logging using an AUTONOMOUS_TRANSACTION procedure that captures FORMAT_CALL_STACK, FORMAT_ERROR_STACK, FORMAT_ERROR_BACKTRACE, input parameters, and session context. The AUTONOMOUS_TRANSACTION is critical β€” without it, the ROLLBACK triggered by the error deletes the log record. Query the error_log table post-incident to reconstruct the full call chain and parameter values. Take the logged parameter values and reproduce the exact failure in a test or staging environment where you CAN attach SQL Developer. Set an exception breakpoint for the error code, pass the logged parameters to the failing procedure, and let the debugger find the line. The production log provides the parameters; the test environment provides the interactivity.
  • QWhat privileges are required for SQL Developer debugging and why might breakpoints still not work even after granting them?JuniorReveal
    Two system privileges are required: DEBUG CONNECT SESSION allows the session to initiate a debug connection, and DEBUG ANY PROCEDURE allows setting breakpoints in compiled objects across all schemas. For least-privilege setups, GRANT DEBUG ON specific_package TO developer replaces DEBUG ANY PROCEDURE for specific objects. On Oracle 12c+, the JDWP privilege is also needed for remote debugging via DBMS_DEBUG_JDWP. Even with all privileges granted, breakpoints silently fail if the procedure was not compiled with the DEBUG flag. The two conditions are independent β€” privileges control what you are allowed to debug, DEBUG compilation controls whether the compiled object contains the symbol table information the debugger needs to bind breakpoints. Missing either one produces silent failure. Verify both: check privileges in dba_sys_privs and debug status in user_procedures WHERE debuginfo = 'YES'.
  • QExplain the architecture of SQL Developer remote debugging β€” which side initiates the TCP connection and why does the firewall direction matter?SeniorReveal
    The database session initiates the outbound TCP connection to SQL Developer using DBMS_DEBUG_JDWP.CONNECT_TCP. SQL Developer listens on a configurable port (default 4000) and accepts the incoming connection. This is counterintuitive β€” you might expect the debugger tool to connect to the database, but it is the opposite. The firewall implication is that the database server must be able to make outbound TCP connections to the SQL Developer workstation on the debug port. Many corporate environments allow outbound TCP from database servers by default, which makes this architecture firewall-friendly. The CONNECT_TCP call blocks until SQL Developer attaches or the timeout expires β€” so SQL Developer must be listening before CONNECT_TCP is called, not after. The common mistake is starting the debug session in SQL Developer after CONNECT_TCP has already timed out, then wondering why nothing is attached.

Frequently Asked Questions

Can I use SQL Developer debugger against a production database?

You should not, for three reasons: (1) DEBUG compilation must be active for breakpoints to work, and debug objects should not exist in production β€” they expose internal variable names and are larger than necessary; (2) the JDWP debug connection holds an open session and adds latency to every step, which affects production workloads; (3) the risk of accidentally modifying data or leaving the session in a mid-transaction state during debugging is not acceptable in production. Instead, implement enhanced error logging using DBMS_UTILITY.FORMAT_CALL_STACK, FORMAT_ERROR_STACK, and FORMAT_ERROR_BACKTRACE in AUTONOMOUS_TRANSACTION blocks. Use the logged parameters to reproduce the issue in a staging environment where you can attach the debugger safely.

Why does my breakpoint not trigger even though the procedure is compiled with DEBUG?

Work through this checklist: (1) Verify the compiled version matches your current source β€” if you edited the procedure after compiling with DEBUG, recompile: ALTER PROCEDURE proc_name COMPILE DEBUG; (2) Confirm the connection in SQL Developer uses the correct schema owner β€” a breakpoint set in SCHEMA_A.PROC will not fire when SCHEMA_B.PROC executes, even if they have identical source; (3) Verify you have DEBUG privilege on the object: SELECT * FROM dba_tab_privs WHERE grantee = 'YOUR_USER' AND privilege = 'DEBUG'; (4) For remote debugging, confirm DBMS_DEBUG_JDWP.CONNECT_TCP was called before the procedure executed and SQL Developer had already started listening; (5) Check the Breakpoints window β€” the breakpoint must show as active (enabled checkbox) and not disabled or skipped.

How do I debug a trigger that raises ORA-06512?

Triggers are debuggable but require a different approach. First, compile the trigger with DEBUG: ALTER TRIGGER trigger_name COMPILE DEBUG. Set a line breakpoint inside the trigger body at the line you want to inspect, or set an exception breakpoint for the expected error code. Then perform the DML operation that fires the trigger (INSERT, UPDATE, or DELETE) through the debug session. The debugger halts when the trigger executes. The Call Stack window will show the trigger as a frame in the stack. One limitation: the Call Stack context for triggers is less detailed than for standalone procedures β€” the triggering DML is shown as the parent frame but without parameter details. Use the Variables window to inspect trigger-level variables including :NEW and :OLD record values.

What is the performance impact of DEBUG compilation in production?

DEBUG compilation increases object size by 10–15% due to embedded symbol tables that map bytecode positions to source lines and variable names. Runtime execution performance when no debugger is attached is identical to non-debug compilation β€” the symbol table is only read when a debugger connects and requests information. The overhead only appears during an active debug session when breakpoints are hit: each breakpoint hit requires the debugger to evaluate the symbol table and transfer variable values over the JDWP connection, which takes 200–500 ms per hit in remote sessions. None of this overhead applies in production unless someone accidentally attaches a debug session to a production database β€” which is why you should never have DEBUG compilation in production regardless of the performance argument.

Can I set a conditional breakpoint that only fires for specific parameter values?

Yes, and this is the correct approach for intermittent errors that occur only under specific data conditions. In the Breakpoints window, right-click a breakpoint and select Properties. In the Condition field, enter a PL/SQL boolean expression such as: p_customer_id IS NULL, p_report_type = 'QUARTERLY_ADJUSTMENT', or v_count = 0. The breakpoint fires only when the condition evaluates to TRUE. Conditions are evaluated at the breakpoint location β€” variables must be in scope. For exception breakpoints, the condition is evaluated at the moment the exception is raised, using the variables in scope at that point. Use conditional breakpoints for batch jobs that process millions of records successfully before hitting the one record that triggers the error β€” without the condition, the debugger would halt on every matching exception, making the session unusable.

How long does DBMS_DEBUG_JDWP.CONNECT_TCP block if SQL Developer is not listening?

CONNECT_TCP blocks for the number of seconds specified in the timeout parameter. The default timeout is implementation-dependent but typically 30–60 seconds if not specified. After the timeout expires, CONNECT_TCP raises an exception (ORA-30671 or a timeout-related error) and execution continues. The defensive wrapper pattern in this guide catches this exception and continues execution without the debugger attached β€” useful in test automation where debugger attachment is optional. Always specify an explicit timeout: DBMS_DEBUG_JDWP.CONNECT_TCP(host => '...', port => 4000, timeout => 30). A blocked CONNECT_TCP call with no timeout can hold up a database session indefinitely if SQL Developer never attaches.

πŸ”₯
Naren Founder & Author

Developer and founder of TheCodeForge. I built this site because I was tired of tutorials that explain what to type without explaining why it works. Every article here is written to make concepts actually click.

← PreviousUsing PRAGMA EXCEPTION_INIT to Map Oracle ErrorsNext β†’Debugging PL/SQL with DBMS_OUTPUT, Exceptions & SQL Developer
Forged with πŸ”₯ at TheCodeForge.io β€” Where Developers Are Forged