When _process_event raised a DB exception (e.g. constraint violation),
PostgreSQL put the whole transaction into ABORTED state. Any subsequent
ORM call (event.mark_processed, Odoo's own flush) then raised
psycopg2.errors.InFailedSqlTransaction, masking the real error.
Fix: wrap _process_event in a database savepoint inside receive_iot_event.
A processing failure now only rolls back the session/device side-effects;
the ows.iot.event record stays committed and the error is stored in
processing_error. The transaction itself remains valid for Odoo's flush.