raising an exception here rather than returning False causes problems with SQLAlchemy's internal state tracking