- Error number
- 402
- Severity
- 16 (user-correctable error)
- State
- 1
- Product
- Microsoft SQL Server Database Engine
- Versions
- All supported SQL Server versions (2016 to 2025), Azure SQL Database, Azure SQL Managed Instance
- Category
- Data Type & Conversion
- Last reviewed
- 24 October 2026
On this page
What it means
Error 402 means an operator such as =, <> or + was given two data types it cannot work with together, typically a legacy text, ntext or image column, an xml value, or a uniqueidentifier joined to a string.
Every comparison and arithmetic operator has a list of type pairs it accepts. When the two operands fall outside that list, SQL Server stops the statement at compile time with 402 at severity 16. The message names both types in the order they appear in your expression and the operator in words: equal to for =, not equal to for <>, add for +. So text and varchar ... equal to means a text column on the left of = and a varchar literal on the right.
The usual culprits are the deprecated text, ntext and image types, which cannot be compared with =, and xml, which cannot be compared with a string at all. Error 402 differs from error 206 (no conversion between two types, for example in an assignment) and from error 8117, which the engine raises when one type is invalid for the operator on its own, such as image + image or date - date.
Common causes
- A WHERE or JOIN that compares a legacy
textorntextcolumn with a string using = or <>. - Building a message with + from a string and a
uniqueidentifier,timeor other type that + cannot combine with text. - Comparing an
xmlcolumn with a string literal instead of querying it with the xml methods. - An
imagecolumn compared with a varbinary value, for example to find duplicate files. - Code written for varchar(max) running against an older copy of the table that still uses text or ntext.
Diagnose it
Read-only These queries only read metadata and dynamic management views. They do not change data, permissions or configuration, so they are safe to run first.
Find text, ntext, image and xml columns in the database
SELECT OBJECT_SCHEMA_NAME(c.object_id) AS schema_name,
OBJECT_NAME(c.object_id) AS table_name,
c.name AS column_name, t.name AS data_type
FROM sys.columns AS c
JOIN sys.types AS t ON t.user_type_id = c.user_type_id
JOIN sys.tables AS tb ON tb.object_id = c.object_id
WHERE t.name IN (N'text', N'ntext', N'image', N'xml')
ORDER BY schema_name, table_name; Every column that cannot take part in a plain = comparison with a string or binary value. The table and column in your failing query should be in this list.
Check the type each side of the operator really has
sp_describe_first_result_set compiles a query without running it. Select each operand on its own to see its type.
EXEC sp_describe_first_result_set
N'SELECT status_note, CAST(status_note AS varchar(max)) AS as_varchar FROM dbo.Tickets;'; system_type_name shows text for the raw column and varchar(max) after the CAST, which = accepts.
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Cast the legacy column to varchar(max) or nvarchar(max) in the query
Read-onlyA quick query-level fix that leaves the table alone. Use nvarchar(max) for ntext and varbinary(max) for image. The cast prevents index use on that column, so treat it as a stopgap.
SELECT id
FROM dbo.Tickets
WHERE CAST(status_note AS varchar(max)) = 'urgent';
Build strings with CONCAT instead of +
Read-onlyCONCAT converts each argument to text first, so it accepts a uniqueidentifier, a time or a number next to a string.
DECLARE @order_ref uniqueidentifier = NEWID();
SELECT CONCAT('Order ', @order_ref) AS label;
Query xml with its methods instead of =
Read-onlyTest the content you care about with exist() or read a value with value(). This compares data, not formatting, which a string comparison of xml would get wrong anyway.
SELECT id
FROM dbo.Jobs
WHERE payload.exist('/job[@type="nightly"]') = 1;
Convert the deprecated column type
Changes schematext, ntext and image are deprecated. Changing them to varchar(max), nvarchar(max) and varbinary(max) removes this whole class of errors. Test on a copy first: the change rewrites a large table and dependent code may need retesting.
ALTER TABLE dbo.Tickets ALTER COLUMN status_note varchar(max) NULL;
Examples
A legacy text column compared with =
CREATE TABLE dbo.Tickets (id INT PRIMARY KEY, status_note TEXT);
SELECT id
FROM dbo.Tickets
WHERE status_note = 'urgent'; -- text cannot be compared with =
Msg 402, Level 16, State 1, Line 3 The data types text and varchar are incompatible in the equal to operator.
Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.
A string joined to a uniqueidentifier with +
DECLARE @order_ref uniqueidentifier = NEWID();
SELECT 'Order ' + @order_ref AS label;
Msg 402, Level 16, State 1, Line 2 The data types varchar and uniqueidentifier are incompatible in the add operator.
Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.
An xml column compared with a string
CREATE TABLE dbo.Jobs (id INT PRIMARY KEY, payload XML);
SELECT id
FROM dbo.Jobs
WHERE payload = N'<job type="nightly"/>';
Msg 402, Level 16, State 1, Line 3 The data types xml and nvarchar are incompatible in the equal to operator.
Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.
How to prevent it
Retire text, ntext and image columns in favour of the max types, and do not create new ones: Microsoft has marked them deprecated for many releases. Store structured documents in xml or JSON only when you plan to query them with the matching functions, not by string comparison.
Use CONCAT or CONCAT_WS for every piece of display text that mixes types; it never trips over operator rules or NULLs. See SQL data types explained for picking modern types.
Common questions
Why does LIKE work on my text column when = does not?
LIKE is one of the few operators the legacy text and ntext types still support, along with IS NULL. Equality, sorting and grouping are not supported, which is why = raises 402 and ORDER BY raises 306.
What is the difference between error 402 and error 8117?
Error 402 names two types that cannot be combined by the operator. Error 8117 names one type that the operator does not accept at all, for example date with the subtract operator.
Is it safe to change a text column to varchar(max)?
The data converts without loss, but the ALTER rewrites the column and can take a long time and a lot of log space on a big table. Run it in a maintenance window after testing on a copy.
Learn more on CodeWithSQL
Official documentation
- ntext, text, and image (Transact-SQL)
- Comparison operators (Transact-SQL)
- exist() method (xml data type)
- Database Engine events and errors 0 to 999
Last technically reviewed 24 October 2026; examples and diagnostics run on SQL Server 2025 (17.0.1145.4). Message text checked against the engine's sys.messages catalogue.