Another solution is to use the ST_Union()
inside of the query (it was also mentioned in
@geozelot's comment), because features from a "cut" layer need to become one geometry (of type MULTIPOLYGON
). This idea was taken from this thread : More on cutting polygons with polygons, in PostGIS.
Let's assume there are two polygon layers called 'grid_test' (green) with nine features and 'grid_test2' (orange) with five features in it, see image below.

So, your query may look like this:
WITH union_gd2 AS (
SELECT
ST_Union(gt2.geometry) as geometry
FROM
"grid_test2" AS gt2
)
SELECT
gd1.id,
st_difference(gd1.geometry, ugd2.geometry) AS geometry
FROM
"grid_test" AS gd1,
"union_gd2" AS ugd2
WHERE
st_isvalid(st_difference(gd1.geometry, ugd2.geometry))
or like this:
SELECT
gd1.id,
st_difference(gd1.geometry, union_gd2.geometry) AS geometry
FROM
"grid_test" AS gd1,
(SELECT
ST_Union(gt2.geometry) as geometry
FROM
"grid_test2" AS gt2
) AS union_gd2
WHERE
st_isvalid(st_difference(gd1.geometry, union_gd2.geometry))
and then get the final output

References: