DEV Community

umzzil nng
umzzil nng

Posted on • Originally published at oraerror.com

Oracle ORA-01436 Error: Causes and Solutions Complete Guide

ORA-01436: CONNECT BY Loop in User Data — Causes, Fixes & Prevention

ORA-01436 is thrown by Oracle when a hierarchical query using the CONNECT BY clause encounters a circular reference in the data — meaning the traversal path loops back to a previously visited node (e.g., A → B → C → A). This prevents Oracle from completing the tree walk and immediately halts query execution with the error. It typically surfaces in tables representing org charts, bill of materials (BOM), or any parent-child relationship structure.


Top 3 Causes

1. Circular Reference Between Multiple Rows

The most common cause: two or more rows reference each other as parent and child, creating an infinite loop during tree traversal.

-- Example: Employee 100's manager is 200, and Employee 200's manager is 100
UPDATE employees SET manager_id = 200 WHERE employee_id = 100;
UPDATE employees SET manager_id = 100 WHERE employee_id = 200;
COMMIT;

-- This query will throw ORA-01436
SELECT employee_id, manager_id, last_name
FROM   employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;
Enter fullscreen mode Exit fullscreen mode

2. Self-Referencing Row

A record that points to itself as its own parent is the simplest form of a loop and is surprisingly common after bulk data loads or migrations.

-- Find self-referencing rows
SELECT employee_id, manager_id, last_name
FROM   employees
WHERE  employee_id = manager_id;

-- Fix: correct the manager_id
UPDATE employees
SET    manager_id = 101
WHERE  employee_id = 100
AND    manager_id  = 100;
COMMIT;
Enter fullscreen mode Exit fullscreen mode

3. Missing NOCYCLE Option in the Query

Even when loop data exists, Oracle provides the NOCYCLE keyword (available since 10g) to gracefully skip cyclic paths. Omitting it causes the query to fail hard instead of handling the situation cleanly.

-- Without NOCYCLE → ORA-01436
SELECT employee_id, LEVEL
FROM   employees
START WITH manager_id IS NULL
CONNECT BY PRIOR employee_id = manager_id;

-- With NOCYCLE → query completes, loops flagged
SELECT employee_id, manager_id, LEVEL,
       CONNECT_BY_ISCYCLE AS is_cycle
FROM   employees
START WITH manager_id IS NULL
CONNECT BY NOCYCLE PRIOR employee_id = manager_id;
Enter fullscreen mode Exit fullscreen mode

Quick Fix Solutions

Step 1 — Immediately unblock the query by adding NOCYCLE:

SELECT employee_id, manager_id,
       SYS_CONNECT_BY_PATH(employee_id, '/') AS path,
       CONNECT_BY_ISCYCLE                    AS is_cycle
FROM   employees
START WITH manager_id IS NULL
CONNECT BY NOCYCLE PRIOR employee_id = manager_id;
Enter fullscreen mode Exit fullscreen mode

Step 2 — Identify all looping records using CONNECT_BY_ISCYCLE = 1, then fix the bad data:

-- Identify problematic rows
SELECT employee_id, manager_id, CONNECT_BY_ISCYCLE AS is_cycle
FROM   employees
START WITH manager_id IS NULL
CONNECT BY NOCYCLE PRIOR employee_id = manager_id
WHERE  CONNECT_BY_ISCYCLE = 1;

-- Correct the circular reference
UPDATE employees
SET    manager_id = <correct_manager_id>
WHERE  employee_id = <problem_employee_id>;
COMMIT;
Enter fullscreen mode Exit fullscreen mode

Step 3 — Add a CHECK constraint to prevent self-references at the database level:

ALTER TABLE employees
ADD CONSTRAINT chk_emp_no_self_ref
CHECK (employee_id <> manager_id);
Enter fullscreen mode Exit fullscreen mode

Prevention Tips

1. Validate before INSERT/UPDATE with a trigger or procedure

Catch circular references before they enter the database by running a proactive check in a BEFORE trigger or a dedicated validation procedure.

CREATE OR REPLACE TRIGGER trg_prevent_cycle
BEFORE INSERT OR UPDATE OF manager_id ON employees
FOR EACH ROW
DECLARE
    v_count NUMBER;
BEGIN
    IF :NEW.manager_id IS NOT NULL THEN
        SELECT COUNT(*)
        INTO   v_count
        FROM   employees
        START WITH employee_id = :NEW.manager_id
        CONNECT BY NOCYCLE PRIOR manager_id = employee_id
        WHERE  employee_id = :NEW.employee_id;

        IF v_count > 0 THEN
            RAISE_APPLICATION_ERROR(-20001,
                'ORA-01436 prevention: circular reference detected.');
        END IF;
    END IF;
END;
/
Enter fullscreen mode Exit fullscreen mode

2. Schedule regular data quality checks

Run a scheduled job (via DBMS_SCHEDULER) after every bulk load or nightly batch to detect loops early, before application users hit the error.

-- Schedule a nightly loop-detection check
BEGIN
    DBMS_SCHEDULER.create_job(
        job_name        => 'JOB_CHECK_HIERARCHY_LOOPS',
        job_type        => 'PLSQL_BLOCK',
        job_action      => q'[
            DECLARE v_cnt NUMBER;
            BEGIN
                SELECT COUNT(*) INTO v_cnt
                FROM   employees
                START WITH manager_id IS NULL
                CONNECT BY NOCYCLE PRIOR employee_id = manager_id
                WHERE  CONNECT_BY_ISCYCLE = 1;
                IF v_cnt > 0 THEN
                    -- Trigger alert / log to monitoring table
                    INSERT INTO dba_alert_log(msg, created_at)
                    VALUES('Circular ref detected: ' || v_cnt || ' rows', SYSDATE);
                    COMMIT;
                END IF;
            END;]',
        repeat_interval => 'FREQ=DAILY;BYHOUR=2;BYMINUTE=0',
        enabled         => TRUE
    );
END;
/
Enter fullscreen mode Exit fullscreen mode

Related Oracle Errors

Error Code Description
ORA-01435 User does not exist — sometimes confused in hierarchy query debugging
ORA-30004 Separator string appears in path value when using SYS_CONNECT_BY_PATH
ORA-01652 Out of temp space — can occur when a very deep loop exhausts temp tablespace

📖 Want a more detailed guide?
Check out the full in-depth version (Korean) on oraerror.com — includes detailed analysis, additional SQL examples, and prevention tips.

Top comments (0)