How to fix Error 466 on Windows Server 2025 / Windows 11

Troubleshooting Guide: SQL Server Error 466 – UNION Not Allowed in Recursive CTE

Why This Error Happens

This error occurs because SQL Server’s recursive common table expression (CTE) syntax strictly enforces that the recursive member can only be combined with the anchor member using UNION ALL, not UNION, INTERSECT, or EXCEPT. The SQL Server query optimizer cannot resolve duplicate elimination logic (which UNION requires) within a recursive execution plan, since each recursive iteration depends on the raw output of the previous one. This is a T-SQL syntax/logic constraint rather than a permissions or configuration issue, meaning it will occur consistently on any instance of SQL Server 2025 regardless of server health.

Step-by-Step Resolution Guide

Step 1: Identify the Offending CTE in Your Query

  • Open the query in SQL Server Management Studio (SSMS) or Azure Data Studio and locate the exact CTE name referenced in the error message (e.g., ‘%.*ls’ will be replaced with your actual CTE name).
  • Look specifically for the section combining the anchor query and the recursive query using the UNION keyword instead of UNION ALL.
  • Example of invalid syntax:
  WITH cte_name AS (
      SELECT col1 FROM table1
      UNION
      SELECT col1 FROM table1 JOIN cte_name ON ...
  )

Step 2: Replace UNION with UNION ALL

  • Edit the query text and change UNION to UNION ALL between the anchor member and the recursive member.
  • Corrected syntax should look like this:
  WITH cte_name AS (
      SELECT col1 FROM table1
      UNION ALL
      SELECT col1 FROM table1 JOIN cte_name ON ...
  )
  SELECT * FROM cte_name;
  • Save the modified script to a local path, such as C:\Scripts\FixedRecursiveCTE.sql, for version control.

Step 3: Handle Duplicate Rows Manually (If Required)

  • Since UNION ALL does not remove duplicates, add a DISTINCT clause to the final outer SELECT statement if your original logic relied on UNION to filter duplicates.
  • Example:
  SELECT DISTINCT * FROM cte_name;
  • Alternatively, use a ROW_NUMBER() window function in the outer query to filter duplicates based on specific business logic rather than filtering the entire row set.

Step 4: Re-execute and Validate Query Plan

  • Run the corrected script in SSMS connected to your Windows Server 2025 instance.
  • Check the Messages tab to confirm Error 466 no longer appears.
  • Review the Actual Execution Plan to ensure the recursive CTE operator now processes correctly without a duplicate “Union” logical operator in the plan tree.

Alternative or Verification Steps

  • Verification: Execute the query with SET STATISTICS PROFILE ON before running the script; confirm the recursive CTE completes without truncation errors and returns the expected row count.
  • Alternative: If deduplication logic is complex, restructure the recursive CTE to use UNION ALL and move the deduplication logic into a separate outer query using GROUP BY on all selected columns instead of DISTINCT, which can offer better performance on large recursive hierarchies.