Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk4 min

Your SQLAlchemy Test Factory Fails at Random Past 50 Rows? Set __set_primary_key__ = False

Intermittent duplicate primary-key errors in SQLAlchemy tests often come from Polyfactory generating random IDs. One setting fixes it, if the diagnosis fits.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If you use Polyfactory’s SQLAlchemyFactory and your tests fail intermittently with IntegrityError: UNIQUE constraint failed: users.id once you generate a few dozen rows, add one line to the factory: __set_primary_key__ = False. That stops the factory from inventing random primary keys, so the database assigns them and the collisions stop.

This fix is conditional. It fits when the project uses Polyfactory and the traceback names a primary-key column. The sections below cover how to check that, why the failure shows up at random, and what to do if your setup differs.

As an Amazon Associate I earn from qualifying purchases.

The fix

from polyfactory.factories.sqlalchemy_factory import SQLAlchemyFactory

class UserFactory(SQLAlchemyFactory[User]):
    __set_primary_key__ = False

Polyfactory’s API reference documents __set_primary_key__ as the flag that controls whether primary-key columns are treated as factory fields. The default is True, so by default the factory generates a value for the key itself. Setting it to False leaves the column unset, and the database or ORM supplies the value when the row is persisted. Apply it to every factory whose model has a generated primary key, or to a shared base factory that your other factories inherit from.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Confirm this is your problem first

“Fails at random past 50 rows” does not identify the cause by itself. Check these before changing anything:

  • The library. __set_primary_key__ exists only in Polyfactory. If your factories subclass factory.alchemy.SQLAlchemyModelFactory, you use factory_boy, and the factory_boy section below applies instead.
  • The exception. It should be an IntegrityError on a uniqueness or primary-key constraint, naming the table and the id column. The wording varies by database. SQLite says UNIQUE constraint failed: users.id, while PostgreSQL reports a duplicate key value violating a unique constraint.
  • The constrained column. If the failing column is an email, username or slug rather than the primary key, this setting will not help. Those columns need their own unique-value strategy.
  • Manual keys. If your tests assign IDs by hand or load fixtures with fixed IDs, the collision may come from your own data and not from the factory.

Why it fails randomly, and only at larger sizes

A Dev Community article with this exact symptom reports that, with Polyfactory 3.3.0 and SQLAlchemy 2.1.1, integer primary keys were filled in using Faker’s pyint(), which the author gives as a range of 0 to 9999. Random draws from a finite range follow the birthday-problem pattern. With only a few rows a collision is unlikely, but each extra row makes one more likely, so the failure seems to appear suddenly and unpredictably as the batch grows. Nothing is wrong with any single row.

As a rough check, a simple birthday estimate for one table drawing from 10,000 values gives about 11% odds of a collision at 50 rows and about 39% at 100. That is arithmetic, not a measurement. The author’s own numbers are higher, which may mean their setup drew more keys than a single table would, for example related rows across several factories.

What the author measured

The article’s author ran 100 repeated attempts per size on fresh SQLite databases and reported these failure counts:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rows generated Failures per 100 runs (author-reported)
50 posts 25 to 36
100 posts 76 to 82
200 posts 100
200 posts with primary-key generation disabled 0

These figures come from one author’s environment and have not been independently reproduced. Treat them as an illustration of the pattern, not a universal threshold. The point where your tests start failing depends on your range, your model and how many related rows you create.

What changes after the fix

With primary-key generation off, the ID is no longer decided in Python. The model’s key column must be one the database can generate, such as an integer primary key with autoincrement behavior. SQLAlchemy usually treats a single integer primary key that way by default, but confirm it for your schema.

One consequence matters for test code. An object created with build() that has not been persisted may still have id = None, because the value only exists after the insert. If a test reads user.id, flush or commit first:

user = UserFactory.build()
session.add(user)
session.flush()   # sends the INSERT; user.id is now populated
assert user.id is not None

Polyfactory’s persistence guide shows factory results being persisted with a non-null ID. SQLAlchemy flushes pending changes automatically before a commit, and you can call Session.flush() yourself when you need the ID earlier, without committing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Related rows and foreign keys

If a child factory needs a parent’s ID, give it the parent object or flush the parent first, so the foreign key is not populated from a still-empty None ID.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Recovering a session after a failed flush

Once an IntegrityError has been raised during a flush, SQLAlchemy requires you to call Session.rollback() before using that session again. If a test fixture reuses a session after a collision, later tests can fail with confusing secondary errors. Fix the primary-key collision first, then make sure fixtures roll back or recreate the session between tests.

If you use factory_boy instead

The __set_primary_key__ flag does not exist in factory_boy. Its SQLAlchemy factory controls persistence with sqlalchemy_session_persistence, which accepts None, "flush" or "commit". For values that must be unique, its recipes recommend declaring a factory.Sequence, which produces ever-increasing values and therefore avoids random collisions.

Polyfactory factory_boy
Relevant setting __set_primary_key__ = False factory.Sequence for unique values; sqlalchemy_session_persistence for persistence
Who creates the primary key The database, once the flag is off You choose: the database, or a sequence you declare
When the ID is available After flush or commit Depends on the persistence mode, or immediately if a sequence assigns it

Checklist

  1. Read the traceback and confirm it is a primary-key or unique violation on the table you expect.
  2. Confirm the factory subclasses Polyfactory’s SQLAlchemyFactory.
  3. Add __set_primary_key__ = False to the factory or a shared base class.
  4. Check that the model’s key column is database-generated.
  5. Flush or commit before reading IDs, and roll back sessions between tests.
  6. Run the large-batch test several times. A random bug needs repeated runs, not one passing run, to be convincing.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.