Skip to content
Microsoft SQL Server

SQL Server Error 4145

An expression of non-boolean type specified where a condition is expected

Applies to: All supported SQL Server versions (2016 to 2025), Azure SQL Database, Azure SQL Managed Instance
Last technically reviewed 24 October 2026 on SQL Server 2025 (17.0.1145.4)
The full message
Msg 4145, Level 15, State 1, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near 'ORDER'.
Other forms of this message
Condition ending the statement before a semicolon (reproduced)
Msg 4145, Level 15, State 1, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near ';'.
WHILE with a number instead of a condition (reproduced)
Msg 4145, Level 15, State 1, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near 'BEGIN'.
Error number
4145
Severity
15 (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
Last reviewed
24 October 2026

What it means

Error 4145 means WHERE, IF, WHILE, CASE WHEN, HAVING or ON was given a plain value such as a bit column instead of a true or false comparison, so the condition is incomplete.

T-SQL has no boolean data type that you can store or select. A condition must be a predicate: a comparison (=, >, <>), IS NULL, LIKE, IN, EXISTS or BETWEEN, combined with AND, OR and NOT. A bit column or variable is a number (0 or 1), not a predicate, so WHERE is_active is rejected by the parser with 4145 at severity 15 and the batch does not run.

The token after near is not the mistake itself but the first thing the parser met after the incomplete condition: ORDER, THEN, PRINT, BEGIN or the closing semicolon. Look immediately to the left of it. The habit usually comes from C#, JavaScript, Python or MySQL, where a number or a flag can be used as a condition directly.

Common causes

  • A bit column used on its own: WHERE is_active or WHERE NOT is_deleted.
  • A flag variable used directly in IF @debug or WHILE @keep_going.
  • CASE WHEN is_active THEN ... without a comparison.
  • A number or function result used as a condition, such as HAVING COUNT(*), WHERE stock or AND LEN(@s).
  • A join with ON p.id where the = other.id part was lost while editing.

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.

Check the column type behind the condition

SELECT c.name AS column_name, TYPE_NAME(c.user_type_id) AS data_type
FROM sys.columns AS c
WHERE c.object_id = OBJECT_ID(N'dbo.Products')
ORDER BY c.column_id;
What to look for

A bit column needs = 1 or = 0; an int column needs a comparison such as > 0, and text needs <> '' or IS NOT NULL, depending on what you mean.

Check the corrected query compiles

EXEC sp_describe_first_result_set
     N'SELECT name FROM dbo.Products WHERE is_active = 1 ORDER BY name;';
What to look for

One row for the name column. The same call reports 4145 while a condition is still incomplete.

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.

Compare flags with = 1 or = 0

Read-only

Write out the comparison. For a nullable bit column, decide how NULL should behave: = 0 does not match NULL rows.

SELECT name
FROM dbo.Products
WHERE is_active = 1
ORDER BY name;

Use explicit comparisons in IF, WHILE and CASE

Read-only

The same rule applies to procedural code and CASE expressions.

DECLARE @debug bit = 1;
IF @debug = 1
    PRINT 'Debug mode';

SELECT name, CASE WHEN is_active = 1 THEN 'yes' ELSE 'no' END AS active
FROM dbo.Products;

Say what a number or text value should satisfy

Read-only

For numbers, decide between > 0 and <> 0; for HAVING, compare the aggregate; for text, test for NULL or emptiness explicitly.

SELECT is_active, COUNT(*) AS products
FROM dbo.Products
WHERE stock > 0
GROUP BY is_active
HAVING COUNT(*) > 1;

Examples

A bit column used as the whole WHERE condition

CREATE TABLE dbo.Products (id INT PRIMARY KEY, name NVARCHAR(50), is_active BIT, stock INT);

SELECT name
FROM dbo.Products
WHERE is_active   -- no comparison
ORDER BY name;
Result
Msg 4145, Level 15, State 1, Line 6
An expression of non-boolean type specified in a context where a condition is expected, near 'ORDER'.

Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.

IF on a bit variable

DECLARE @debug bit = 1;
IF @debug
    PRINT 'Debug mode';
Result
Msg 4145, Level 15, State 1, Line 3
An expression of non-boolean type specified in a context where a condition is expected, near 'PRINT'.

Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.

CASE WHEN without a comparison

CREATE TABLE dbo.Products (id INT PRIMARY KEY, name NVARCHAR(50), is_active BIT, stock INT);

SELECT name,
       CASE WHEN is_active THEN 'yes' ELSE 'no' END AS active
FROM dbo.Products;
Result
Msg 4145, Level 15, State 1, Line 4
An expression of non-boolean type specified in a context where a condition is expected, near 'THEN'.

Reproduced on SQL Server 2025 (17.0.1145.4), 23 October 2026.

How to prevent it

Treat every condition as a question with an explicit comparison, even for flags. It reads clearly, ports between database engines, and forces a decision about NULL rows. Compile new queries with sp_describe_first_result_set or a quick run against an empty test table before they reach a deployment script.

For how WHERE conditions are built from comparisons, see the SQL WHERE clause explained and the CASE expression reference.

Common questions

Does SQL Server have a boolean type?

Not one you can store or select. bit holds 0, 1 or NULL and behaves like a number. Conditions produce true, false or unknown internally, but you must write them as comparisons or predicates.

Why does the message point at ORDER or THEN when the mistake is earlier?

The parser only notices the condition is incomplete when it reaches the next keyword. The real problem is the expression just before the quoted token.

WHERE is_active works in MySQL. Why not in SQL Server?

MySQL treats any non-zero number as true in a condition. SQL Server requires a predicate, so write WHERE is_active = 1.

Learn more on CodeWithSQL

Official documentation

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.

Still stuck on a SQL Server error?

Browse the full SQL Server error library, or get hands-on help from an experienced SQL professional.