I'm inclinded to think this is a bug and I have reported it.
context paramater you pass to
bmesh.ops.delete would appear to correspond to deleting faces (DEL_FACES), this isn't documented clearly but appears to match with the enum defined in bmesh_operator.h. Ideally this enum should be defined in python for use with this operator.
By passing a geom list as well as a context, there are times (not every time) when an item can be deleted multiple times. It may be expecting to use one of these paramaters - not both.
You can verify this by deselecting all geometry before running the script. Removing the context paramater or changing it to 1,2 or 4 also works. It would also appear that if the selected items matches the
geom paramater there is no problem, you can test this by deselecting the faces in your loop and selecting the faces as you add them to the list.
So this also works -
delete_first = 
for f in bm.faces:
f.select = False
if f.calc_center_bounds().y < 0:
f.select = True
bmesh.ops.delete(bm, geom=delete_first, context=5)
From the response to the bug report it seems that passing duplicate geom to
bisect_plane is the cause of the duplicate error message, though I seem to have trouble creating another scenario that causes a crash. The bmesh data created by the bisect isn't guaranteed to be appended to the end of the geom list so copying the geom based on the index relative to previous list lengths is creating duplicates. You will need to look at what you want to do after what you have so far to see how to work out another way to update the geom list.