Troubleshooting SQLAlchemy

Here is a growing list of common issues and solutions for SQLAlchemy.

Adding this object again causes a unique constraint violation

This is a common issue when you are trying to add an object to the session that is already on the DB. Instead, use merge, and make sure to assign the merged object to a variable (often with the same name) and keep using that. There’s no real advantage to using session.add() over session.merge().

Example:

obj = session.merge(obj)

Parent not in session, update along children is not updated in the database (Warning only)

This is a warning that tells you that even though you added / deleted a child object, the relationship cannot automatically update the object in the database, because the parent is not connected to a session.

This is sometimes important but a lot of times meaningless. For example, if you deleted Parent, and then go on to remove the children from it, it makes little difference that the relationship is no longer emitting SQL changes, because the parent is going to be deleted anyway.

When initializing mapper Mapper[...], expression '...' failed to locate a name

This happens when a related object class is not imported when the relationship needs to be instantiated.

When two classes, A and B, are related to each other, we would see a definition like this:

class A(Base):
    __tablename__ = 'a'
    id = Column(Integer, primary_key=True)
    b_id = Column(Integer, ForeignKey('b.id'))
    b = relationship('B')

class B(Base):
    __tablename__ = 'b'
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('a.id'))
    a = relationship('A')

Notice that the relationship function is called with a string argument. This is because the class B is not defined yet when the class A is defined. This solves a “chicken and egg” problem, by making a promise to the mapper that when the relationships are instatiated, both classes will have been imported.

If some of the related objects are on a different file (module) and that file is not imported by any of the code you are running, you will get the error above.

This usually happens on scripts and parallel pipelines that only use a subset of the classes. To fix this, simply import the missing class module at the beginning of the script.

Changing the primary key of an object causes update instead of new object

For objects that don’t have an auto-incrementing primary key (e.g., Provenance), the user is in control of the value that goes into the primary key. Sometimes, the user changes this value, e.g., when a Provenance gets new parameters and the update_id() method is called.

If the object is already in the session, and the primary key is changed, SQLAlchemy will update the object in the database, instead of creating a new one. This will remove the old object and may cause problems with objects that relate to that row in the table.

Make sure to detach your object, or make a brand new one and copy properties over to the new instance before merging it back into the session as a new object.

Deadlocks when querying the database

This can occur when an internal session is querying the same objects that an external session is using. In general, you should not be opening an internal session when a different one is open, instead, pass the session as an argument into the lower scope so all functions use the same session.

If the app freezes, check for a deadlock: Go into the DB and do select * from pg_locks; to see if there are many locks.

Sometimes using SELECT pg_cancel_backend(pid) FROM pg_locks; will free the lock. Otherwise, try to restart the psql service.