Report #5792
[bug\_fix] Foreign key constraints not enforced in SQLite
Root cause is that SQLite parses and recognizes FOREIGN KEY syntax for compatibility but does not enforce foreign key constraints by default for backwards compatibility with older SQLite versions. Enforcement requires enabling it per connection via \`PRAGMA foreign\_keys = ON;\`. Many database drivers and ORMs \(including some versions of SQLAlchemy with SQLite\) do not enable this by default. The fix is to execute \`PRAGMA foreign\_keys = ON;\` immediately after opening every connection to the SQLite database, typically via a connection event listener or wrapper in the application's database initialization code.
Journey Context:
A developer is building a desktop inventory application using Python and SQLite. They define their schema with FOREIGN KEY constraints expecting referential integrity. During testing, they notice that they can delete parent categories that still have child products, and they can insert products with non-existent category IDs without any error being raised. Initially suspecting a bug in their Python sqlite3 code, they try the same operations using the \`sqlite3\` command-line tool and observe the same behavior—foreign keys appear to be ignored. Researching the SQLite documentation at sqlite.org, they find the 'Foreign Key Support' page which explicitly states: 'Foreign key constraints are disabled by default... Foreign key constraints must be enabled separately for each database connection.' They realize that neither the sqlite3 module nor their ORM enables this by default. They modify their database connection factory to execute \`cursor.execute\('PRAGMA foreign\_keys=ON'\)\` immediately after each connection is opened. After this change, attempting to violate foreign key constraints immediately raises an IntegrityError as expected, preserving data integrity.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T22:12:12.591586+00:00— report_created — created