Fix Error 1785 “Introducing FOREIGN KEY constraint … may cause cycles or multiple cascade paths” in SQL Server

If you’re getting SQL Server error 1785 that reads something like “Introducing FOREIGN KEY constraint ‘FK__Name’ on table ‘Department’ may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints“, it’s probably because you’ve specified the CASCADE option when trying to create a foreign key with a circular reference, or one that has multiple cascade paths (perhaps your child table has multiple foreign keys to the same primary key on the parent table).

SQL Server error 1785 occurs when creating or modifying foreign key constraints that could potentially cause cyclic or multiple cascade paths. This error is a safeguard against complex delete or update operations that might lead to unpredictable results or infinite loops.

Cause of the Error

The error typically happens in two scenarios:

  1. Cyclic references between tables
  2. Multiple cascade paths to the same table

Example of Error

Consider the following table structure:

CREATE TABLE Department (
    DepartmentID INT PRIMARY KEY,
    Name VARCHAR(50),
    ManagerID INT
);

CREATE TABLE Employee (
    EmployeeID INT PRIMARY KEY,
    Name VARCHAR(50),
    DepartmentID INT,
    FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID) ON DELETE CASCADE
);

So far, so good.

Now let’s add another foreign key:

ALTER TABLE Department
ADD FOREIGN KEY (ManagerID) REFERENCES Employee(EmployeeID) ON DELETE CASCADE;

Output:

Msg 1785, Level 16, State 0, Line 2
Introducing FOREIGN KEY constraint 'FK__Departmen__Manag__2C88998B' on table 'Department' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Msg 1750, Level 16, State 1, Line 2
Could not create constraint or index. See previous errors.

We actually got two error messages, but the first one is the one that explains it.

In this example, we have a cyclic reference between Department and Employee. If we try to delete an employee who is a manager, it could potentially delete the department, which would then delete all employees in that department, including the original employee we tried to delete. Probably not what we want.

Solution 1: Use ON DELETE NO ACTION

The simplest solution is to use ON DELETE NO ACTION for one of the foreign key constraints:

ALTER TABLE Department
ADD FOREIGN KEY (ManagerID) REFERENCES Employee(EmployeeID) ON DELETE NO ACTION;

This prevents the cascading delete from continuing indefinitely.

This is actually the default option, so omitting the ON DELETE argument altogether would suffice.

Solution 2: Use ON DELETE SET NULL

Another option is to use ON DELETE SET NULL:

CREATE TABLE Department (
    DepartmentID INT PRIMARY KEY,
    Name VARCHAR(50),
    ManagerID INT
);

CREATE TABLE Employee (
    EmployeeID INT PRIMARY KEY,
    Name VARCHAR(50),
    DepartmentID INT,
    FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID) ON DELETE SET NULL
);

ALTER TABLE Department
ADD FOREIGN KEY (ManagerID) REFERENCES Employee(EmployeeID) ON DELETE SET NULL;

In this setup, if an employee is deleted, the DepartmentID in the Employee table and the ManagerID in the Department table will be set to NULL rather than causing a cascading delete.

Solution 3: Use Triggers for Complex Logic

If you need more complex logic that can’t be achieved with SET NULL or other built-in options, you can use triggers:

CREATE TRIGGER trg_DeleteDepartment
ON Department
INSTEAD OF DELETE
AS
BEGIN
    -- Custom logic to handle deletions
    -- For example, set employee's department to NULL instead of deleting
    UPDATE Employee
    SET DepartmentID = NULL
    WHERE DepartmentID IN (SELECT DepartmentID FROM deleted);

    -- Then delete the department
    DELETE FROM Department
    WHERE DepartmentID IN (SELECT DepartmentID FROM deleted);
END;

The result of this solution is similar to the previous one (it sets the DepartmentID to NULL), but this example is just to demonstrate how we can create a trigger in case we want more control over the deletion process, especially when we need to implement business logic that goes beyond simple NULL settings.

Solution 4: Redesign the Database Schema

Sometimes when we get errors about circular references or multiple cascade paths, it’s an opportunity to revisit our database schema and see if we can improve it in some way.

For example in our case, we could add a junction table (DepartmentManager) that takes care of the relationship:

CREATE TABLE Department (
    DepartmentID INT PRIMARY KEY,
    Name VARCHAR(50)
);

CREATE TABLE Employee (
    EmployeeID INT PRIMARY KEY,
    Name VARCHAR(50),
    DepartmentID INT,
    FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID) ON DELETE CASCADE
);

CREATE TABLE DepartmentManager (
    DepartmentID INT,
    ManagerID INT,
    FOREIGN KEY (DepartmentID) REFERENCES Department(DepartmentID) ON DELETE CASCADE,
    FOREIGN KEY (ManagerID) REFERENCES Employee(EmployeeID) ON DELETE NO ACTION
);

This design separates the manager relationship into a separate table. Depending on the scenario, this might be a more desirable schema than the previous one, but it doesn’t necessarily solve the above error. For example:

  • The ON DELETE NO ACTION on the ManagerID foreign key is still necessary to prevent the error 1785.
  • If you change this to ON DELETE CASCADE, you’ll encounter the same error, as the circular reference still exists logically.

The benefit of this design is that it makes the relationships clearer and allows for easier management of department-manager assignments. However as mentioned, it doesn’t inherently solve the circular reference issue without also using ON DELETE NO ACTION or similar strategies.