SQLite returns a result code from every API call. The 30 or so primary codes each cover a broad kind of failure. Extended codes carry the primary code in their low eight bits and say more about the cause, so SQLITE_CONSTRAINT_UNIQUE (2067) is a kind of SQLITE_CONSTRAINT (19). Mistakes in the SQL itself all come back as SQLITE_ERROR, with the details in the message.
105 codes from the SQLite Result and Error Codes
SQLITE_IOERR SQLITE_IOERR_READ SQLITE_IOERR_SHORT_READ SQLITE_IOERR_WRITE SQLITE_IOERR_FSYNC SQLITE_IOERR_DIR_FSYNC SQLITE_IOERR_TRUNCATE SQLITE_IOERR_FSTAT SQLITE_IOERR_UNLOCK SQLITE_IOERR_RDLOCK SQLITE_IOERR_DELETE SQLITE_IOERR_BLOCKED SQLITE_IOERR_NOMEM SQLITE_IOERR_ACCESS SQLITE_IOERR_CHECKRESERVEDLOCK SQLITE_IOERR_LOCK SQLITE_IOERR_CLOSE SQLITE_IOERR_DIR_CLOSE SQLITE_IOERR_SHMOPEN SQLITE_IOERR_SHMSIZE SQLITE_IOERR_SHMLOCK SQLITE_IOERR_SHMMAP SQLITE_IOERR_SEEK SQLITE_IOERR_DELETE_NOENT SQLITE_IOERR_MMAP SQLITE_IOERR_GETTEMPPATH SQLITE_IOERR_CONVPATH SQLITE_IOERR_VNODE SQLITE_IOERR_AUTH SQLITE_IOERR_BEGIN_ATOMIC SQLITE_IOERR_COMMIT_ATOMIC SQLITE_IOERR_ROLLBACK_ATOMIC SQLITE_IOERR_DATA SQLITE_IOERR_CORRUPTFS SQLITE_CONSTRAINT SQLITE_CONSTRAINT_CHECK SQLITE_CONSTRAINT_COMMITHOOK SQLITE_CONSTRAINT_FOREIGNKEY SQLITE_CONSTRAINT_FUNCTION SQLITE_CONSTRAINT_NOTNULL SQLITE_CONSTRAINT_PRIMARYKEY SQLITE_CONSTRAINT_TRIGGER SQLITE_CONSTRAINT_UNIQUE SQLITE_CONSTRAINT_VTAB SQLITE_CONSTRAINT_ROWID SQLITE_CONSTRAINT_PINNED SQLITE_CONSTRAINT_DATATYPE