"Attempt to insert record" error caused by PageDoktypeRegistry called in ext_localconf.php in TYPO3 13.4
TL;DR: After updating to TYPO3 13.4, if you see Attempt to insert record on pages:X where table "tt_content" is not allowed,
it might be, that an extension is calling PageDoktypeRegistry::add() in ext_localconf.php instead of ext_tables.php.
Move the call to ext_tables.php to fix it.
The problem
After updating a TYPO3 installation from 12.4 to 13.4, I could no longer save any content elements. TYPO3 always showed errors like:
Attempt to insert record on pages:1 where table "tt_content" is not allowed
Only a few hardcoded record types (like pages itself) could still be saved. Anything content-related on a standard
page was blocked.
After some hours of debugging, I found out the reason for the problem. An extension was calling
PageDoktypeRegistry::add() in ext_localconf.php instead of ext_tables.php. After moving the call to
ext_tables.php, everything worked again.
In-depth analysis
I was curious why this happened, so I dug a little bit into the code.
TYPO3 12 introduced PageDoktypeRegistry as the central place to register which record tables are allowed on which
page doktypes. The registry auto-discovers allowed tables from TCA on first use via an internal initializeTca()
method, but only once. It sets a tcaHasBeenInitialized flag permanently for the current request lifecycle.
The problem is the boot order TYPO3 loads extension files:
- All
ext_localconf.phpfiles are executed. No TCA available yet - TcaFactory compiles and populates
$GLOBALS['TCA'] - All
ext_tables.phpfiles are executed. TCA is fully available
If any extension calls PageDoktypeRegistry::add() from ext_localconf.php, this triggers initializeTca() before
TCA exists. The factory returns empty schemas, so no tables are auto-discovered from TCA (including tt_content),
which relies on its 'security' => ['ignorePageTypeRestriction' => true] TCA configuration to be registered.
Worse, the initialization lock is then permanently set, so when ext_tables.php runs later
(correctly, after TCA is loaded), the auto-discovery step is silently skipped entirely.
The end state: tt_content is never added to the allowed tables for doktype 1 (standard page), and
DataHandler::isTableAllowedOnPage() rejects every content element insert.
