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;
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;
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;
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;
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;
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);
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;
/
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;
/
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)