How to Handle NULLs in PySpark (Use .isNull(), Not == None)
Filtering for NULL values in PySpark with == None silently returns zero rows - every time, for every row. SQL semantics mean anything == NULL evaluates to NULL, not True. The fix is .isNull(). Here's why it works that way and how to get it right.
Why == None always returns nothing
In standard Python, x == None works as you'd expect. In PySpark (and any
SQL-based engine including DuckDB's Spark-compatible API), the comparison
follows SQL NULL semantics:
NULL == NULL -> NULL (not True)
NULL == 'foo' -> NULL (not False)
The filter() call drops any row where the condition evaluates to anything
other than True - including NULL. So F.col("end_date") == None evaluates
to NULL for every row that has a NULL end_date, and those rows are filtered
out instead of kept. The result: zero rows, and no error message.
The correct pattern: .isNull() and .isNotNull()
PySpark's Column class has dedicated methods for NULL checks:
from pyspark.sql import SparkSession
import pyspark.sql.functions as F
spark = SparkSession.builder.getOrCreate()
df = spark.read.option("header", True).csv("subscriptions.csv")
# Wrong - always returns 0 rows when end_date can be NULL
# active = df.filter(F.col("end_date") == None)
# Correct - returns rows where end_date IS NULL (active subscriptions)
active = df.filter(F.col("end_date").isNull())
active.show()
To find rows where the column is NOT NULL (expired subscriptions):
expired = df.filter(F.col("end_date").isNotNull())
The same rule applies in SQL expressions
If you write PySpark queries using spark.sql() or .filter() with a SQL
string, the same rule applies - use IS NULL, not = NULL:
# SQL string form - also correct
active = df.filter("end_date IS NULL")
expired = df.filter("end_date IS NOT NULL")
WHERE end_date = NULL in SQL is a no-op for the same reason: the comparison
returns NULL, so no rows match.
How to spot this bug quickly
The signature of the == None bug is a filter that returns zero rows when
you know the column has NULL values. Cross-check with:
# Count NULLs in the column - should be > 0 if the bug is present
df.filter(F.col("end_date").isNull()).count()
If that count is positive but your equality filter returned zero, you've found the cause.
Linter coverage
pyspark-stubs and ruff (with the pandas-vet plugin) flag == None
comparisons on DataFrame columns. Adding these to your CI catches the pattern
before it reaches production.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Replacing
== Nonewith.isNull()in a PySpark filter - Using
.isNotNull()to filter for non-NULL rows - Debugging a filter that returns zero rows by counting NULLs directly
FAQ
Why does PySpark filter return 0 rows when I filter for None?
PySpark uses SQL NULL semantics. F.col('x') == None evaluates to NULL for every row where x is NULL - not True. The filter drops any row that doesn't evaluate to True, so all NULL rows vanish. Use F.col('x').isNull() instead.
How do I filter for NULL values in a PySpark DataFrame?
Use .isNull() to keep rows where the column is NULL, and .isNotNull() to keep rows where it is not. In a SQL string filter, use IS NULL and IS NOT NULL. Never use == None or = NULL.
Does this problem also apply to DuckDB or Spark SQL?
Yes - any SQL-based engine (DuckDB, Spark SQL, PostgreSQL, BigQuery) follows the same NULL semantics. = NULL always evaluates to NULL, never True. Use IS NULL in SQL and .isNull() in the DataFrame API.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →