Environment
- TYPO3: 12.4.44
- content_defender: 3.5.3
- DCE (t3/dce): 3.3.0
- PHP: 8.2
Description
When adding an element to a DCE FlexForm repeater (section container) via the AJAX endpoint /record/flex/containeradd, a 500 error is thrown:
InvalidArgumentException #1437991120: uid is already set to 1 and does not start with NEW for a "new" command
in DatabaseUniqueUidNewRow.php line 45
This worked correctly with TYPO3 12.4.32 and breaks with TYPO3 12.4.44.
Root cause
In BackendLayoutConfiguration::createFromPageId(), there is a known hack (documented with a // TODO comment) that sets $_GET['id'] globally:
// TODO: Mitigate a problem in \TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher::determinePageId
// @see: https://github.com/IchHabRecht/content_defender/issues/91
if (($_POST['id'] ?? $_GET['id'] ?? null) === null) {
$_GET['id'] = $pageId;
}
During the containeradd AJAX call, this method is called with pageId=0 (because effectivePid=0 at that point in the FormEngine compilation chain). This sets $_GET['id'] = 0 globally, which corrupts the FormEngine compilation and causes databaseRow['uid'] to resolve to 1 instead of the real record UID.
This then cascades into:
- Wrong
effectivePid (0 instead of real page pid)
- Wrong
parentPageRow (null)
- Permission check fails for non-admin users (
AccessDeniedRootNodeException)
uid is already set to 1 exception for new records
Proposed fix
Save and restore $_GET['id'] around the call, so it doesn't leak globally:
$previousGetId = $_GET['id'] ?? null;
if (($_POST['id'] ?? $_GET['id'] ?? null) === null) {
$_GET['id'] = $pageId;
}
$backendLayoutView = GeneralUtility::makeInstance(BackendLayoutView::class);
$backendLayout = $backendLayoutView->getSelectedBackendLayout($pageId);
if (null === $backendLayout) {
$backendLayout = [
'config' => '',
];
}
// Restore $_GET['id'] to avoid corrupting other processes (e.g. FormFlexAjaxController)
if ($previousGetId === null) {
unset($_GET['id']);
} else {
$_GET['id'] = $previousGetId;
}
return new self($backendLayout);
This fix alone is unfortunately not sufficient with TYPO3 12.4.44 — additional patches to DatabaseEditRow and FormFlexAjaxController were also needed in our case. But fixing the global $_GET['id'] mutation is the correct first step.
Related issues
Workaround
Apply the patch above manually to Classes/BackendLayout/BackendLayoutConfiguration.php.
Environment
Description
When adding an element to a DCE FlexForm repeater (section container) via the AJAX endpoint
/record/flex/containeradd, a 500 error is thrown:This worked correctly with TYPO3 12.4.32 and breaks with TYPO3 12.4.44.
Root cause
In
BackendLayoutConfiguration::createFromPageId(), there is a known hack (documented with a// TODOcomment) that sets$_GET['id']globally:During the
containeraddAJAX call, this method is called withpageId=0(becauseeffectivePid=0at that point in the FormEngine compilation chain). This sets$_GET['id'] = 0globally, which corrupts the FormEngine compilation and causesdatabaseRow['uid']to resolve to1instead of the real record UID.This then cascades into:
effectivePid(0 instead of real page pid)parentPageRow(null)AccessDeniedRootNodeException)uid is already set to 1exception for new recordsProposed fix
Save and restore
$_GET['id']around the call, so it doesn't leak globally:This fix alone is unfortunately not sufficient with TYPO3 12.4.44 — additional patches to
DatabaseEditRowandFormFlexAjaxControllerwere also needed in our case. But fixing the global$_GET['id']mutation is the correct first step.Related issues
Workaround
Apply the patch above manually to
Classes/BackendLayout/BackendLayoutConfiguration.php.