What it means
In T-SQL, a condition has to be a predicate: a comparison (=, <>, <…), IN, LIKE,
BETWEEN, EXISTS or IS [NOT] NULL, joined with AND, OR and NOT. A column, a variable, a
number or a function call on its own isn’t one, even when it holds 1 or 0. WHERE, ON, HAVING,
IF, WHILE, CASE WHEN and the first argument of IIF all need a condition, so SQL Server
rejects the batch and runs none of it:
Msg 4145, Level 15, State 1, Server 7732422b7f56, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near ';'.
The near part is where SQL Server expected the rest of the condition; often that’s the ;, THEN,
PRINT or closing bracket right after it.
Common causes
- A
bitcolumn or variable used as a flag:WHERE active,WHERE @include_archived.bitis a number (0, 1 or NULL), not a true/false value. - Habits from other databases:
WHERE TRUE,WHERE email(meaning “has an email”), PostgreSQL’sILIKE(4145 near'ILIKE'). - Half a condition:
WHERE name = N'Ada' OR N'Lin', orON o.customer_idwith nothing to compare it with. IFon a count:IF (SELECT COUNT(*) FROM …) PRINT ….- A row-value comparison:
WHERE (id, name) IN (SELECT …), which T-SQL doesn’t support (4145 near','). - A function that returns
bitused directly:WHERE dbo.is_active(id).
How to fix it
Compare explicitly
| Instead of | Write |
|---|---|
WHERE active | WHERE active = 1 |
WHERE @include_archived | WHERE @include_archived = 1 |
WHERE email | WHERE email IS NOT NULL (and AND email <> '' if empty strings count as missing) |
WHERE TRUE | WHERE 1 = 1 |
WHERE name = N'Ada' OR N'Lin' | WHERE name IN (N'Ada', N'Lin') |
ON o.customer_id | ON o.customer_id = c.id |
CASE WHEN email THEN … | CASE WHEN email IS NOT NULL THEN … |
IIF(active, 'yes', 'no') | IIF(active = 1, 'yes', 'no') |
WHERE dbo.is_active(id) | WHERE dbo.is_active(id) = 1 |
Use EXISTS for “are there any rows”
IF EXISTS (SELECT 1 FROM dbo.orders WHERE status = 'new')
PRINT 'new orders waiting';
EXISTS stops at the first row; (SELECT COUNT(*) …) > 0 also works but counts them all.
Replace row-value IN with EXISTS
SELECT c.id
FROM dbo.customers AS c
WHERE EXISTS (SELECT 1 FROM dbo.orders AS o
WHERE o.customer_id = c.id AND o.status = 'paid');
ILIKE: use LIKE
Under the usual case-insensitive collations (SQL_Latin1_General_CP1_CI_AS, the default on our test
servers), LIKE already ignores case. On a case-sensitive column, compare LOWER(name) LIKE N'a%',
or add COLLATE with a _CI_ collation.
Reproduce it
On SQL Server 2022 (16.0.4295.3) with sqlcmd, each statement in its own batch:
SELECT id FROM seo_err_mssql.customers WHERE email;
SELECT id FROM seo_err_mssql.customers WHERE name ILIKE N'a%';
SELECT CASE WHEN email THEN 'has email' ELSE 'none' END FROM seo_err_mssql.customers;
IF (SELECT COUNT(*) FROM seo_err_mssql.customers) PRINT 'rows';
SELECT id FROM seo_err_mssql.customers WHERE (id, name) IN (SELECT customer_id, status FROM seo_err_mssql.orders);
Msg 4145, Level 15, State 1, Server 7732422b7f56, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near ';'.
Msg 4145, Level 15, State 1, Server 7732422b7f56, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near 'ILIKE'.
Msg 4145, Level 15, State 1, Server 7732422b7f56, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near 'THEN'.
Msg 4145, Level 15, State 1, Server 7732422b7f56, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near 'PRINT'.
Msg 4145, Level 15, State 1, Server 7732422b7f56, Line 1
An expression of non-boolean type specified in a context where a condition is expected, near ','.
WHERE TRUE, WHERE @active (a bit variable set to 1), ON o.customer_id,
WHERE name = N'Ada' OR N'Lin', HAVING COUNT(*) and WHERE dbo.order_count(id) all failed near
';', and IIF(email, 1, 0) near '('. Rewritten as
@active = 1 AND email IS NOT NULL AND name IN (N'Ada', N'Lin') AND name LIKE N'a%', the query
returned Ada, so LIKE ignored case on this collation; WHERE 1 = 1 returned all three customers.
SQL Server 2019 and SQL Server 2025 printed the same messages: none of them accepts TRUE or a bare
bit as a condition.
In Inlet
When SQL Server rejects the batch, Inlet shows its message with
SQL Server error 4145, state 1, severity 15 and links to this page. With your own Anthropic API
key, Ask Claude (Pro, ⌘L) can fix a failed statement, and writes T-SQL when you’re translating a
query from PostgreSQL or MySQL; it sends the schema and the SQL, never rows.