diff --git a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
index 2ae2141493eb8fe0d59f17dfdbbf99df49ce5940..86f4fb5edf5dbd7907702e7318b2e896a113989b 100644
--- a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
+++ b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
@@ -1024,6 +1024,17 @@ class EditDocumentController
                 $body .= '</form>';
             }
         }
+
+        if ($this->firstEl === null) {
+            // In case firstEl is null, no edit form could not be created. Therefore, add an
+            // info box and remove the spinner, since it will never be resolved by FormEnigne.
+            $this->moduleTemplate->setUiBlock(false);
+            $body .= $this->getInfobox(
+                $this->getLanguageService()->getLL('noEditForm.message'),
+                $this->getLanguageService()->getLL('noEditForm'),
+            );
+        }
+
         // Access check...
         // The page will show only if there is a valid page and if this page may be viewed by the user
         $this->pageinfo = BackendUtility::readPageAccess($this->viewId, $this->perms_clause) ?: [];
@@ -1074,150 +1085,159 @@ class EditDocumentController
         $beUser = $this->getBackendUser();
         // Traverse the GPvar edit array tables
         foreach ($this->editconf as $table => $conf) {
-            if (is_array($conf) && $GLOBALS['TCA'][$table] && $beUser->check('tables_modify', $table)) {
-                // Traverse the keys/comments of each table (keys can be a comma list of uids)
-                foreach ($conf as $cKey => $command) {
-                    if ($command === 'edit' || $command === 'new') {
-                        // Get the ids:
-                        $ids = GeneralUtility::trimExplode(',', $cKey, true);
-                        // Traverse the ids:
-                        foreach ($ids as $theUid) {
-                            // Don't save this document title in the document selector if the document is new.
-                            if ($command === 'new') {
-                                $this->dontStoreDocumentRef = 1;
-                            }
-
-                            try {
-                                $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
-                                $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
-                                $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
-
-                                // Reset viewId - it should hold data of last entry only
-                                $this->viewId = 0;
+            if (!is_array($conf) || !($GLOBALS['TCA'][$table] ?? false)) {
+                // Skip for invalid config or in case no TCA exists
+                continue;
+            }
+            if (!$beUser->check('tables_modify', $table)) {
+                // Skip in case the user has insufficient permissions and increment the error counter
+                $this->errorC++;
+                continue;
+            }
+            // Traverse the keys/comments of each table (keys can be a comma list of uids)
+            foreach ($conf as $cKey => $command) {
+                if ($command !== 'edit' && $command !== 'new') {
+                    // Skip if invalid command
+                    continue;
+                }
+                // Get the ids:
+                $ids = GeneralUtility::trimExplode(',', $cKey, true);
+                // Traverse the ids:
+                foreach ($ids as $theUid) {
+                    // Don't save this document title in the document selector if the document is new.
+                    if ($command === 'new') {
+                        $this->dontStoreDocumentRef = 1;
+                    }
 
-                                $formDataCompilerInput = [
-                                    'tableName' => $table,
-                                    'vanillaUid' => (int)$theUid,
-                                    'command' => $command,
-                                    'returnUrl' => $this->R_URI,
-                                ];
-                                if (is_array($this->overrideVals) && is_array($this->overrideVals[$table])) {
-                                    $formDataCompilerInput['overrideValues'] = $this->overrideVals[$table];
-                                }
-                                if (!empty($this->defVals) && is_array($this->defVals)) {
-                                    $formDataCompilerInput['defaultValues'] = $this->defVals;
-                                }
+                    try {
+                        $formDataGroup = GeneralUtility::makeInstance(TcaDatabaseRecord::class);
+                        $formDataCompiler = GeneralUtility::makeInstance(FormDataCompiler::class, $formDataGroup);
+                        $nodeFactory = GeneralUtility::makeInstance(NodeFactory::class);
+
+                        // Reset viewId - it should hold data of last entry only
+                        $this->viewId = 0;
+
+                        $formDataCompilerInput = [
+                            'tableName' => $table,
+                            'vanillaUid' => (int)$theUid,
+                            'command' => $command,
+                            'returnUrl' => $this->R_URI,
+                        ];
+                        if (is_array($this->overrideVals) && is_array($this->overrideVals[$table])) {
+                            $formDataCompilerInput['overrideValues'] = $this->overrideVals[$table];
+                        }
+                        if (!empty($this->defVals) && is_array($this->defVals)) {
+                            $formDataCompilerInput['defaultValues'] = $this->defVals;
+                        }
 
-                                $formData = $formDataCompiler->compile($formDataCompilerInput);
+                        $formData = $formDataCompiler->compile($formDataCompilerInput);
 
-                                // Set this->viewId if possible
-                                if ($command === 'new'
-                                    && $table !== 'pages'
-                                    && !empty($formData['parentPageRow']['uid'])
-                                ) {
-                                    $this->viewId = $formData['parentPageRow']['uid'];
-                                } else {
-                                    if ($table === 'pages') {
-                                        $this->viewId = $formData['databaseRow']['uid'];
-                                    } elseif (!empty($formData['parentPageRow']['uid'])) {
-                                        $this->viewId = $formData['parentPageRow']['uid'];
-                                    }
-                                }
+                        // Set this->viewId if possible
+                        if ($command === 'new'
+                            && $table !== 'pages'
+                            && !empty($formData['parentPageRow']['uid'])
+                        ) {
+                            $this->viewId = $formData['parentPageRow']['uid'];
+                        } else {
+                            if ($table === 'pages') {
+                                $this->viewId = $formData['databaseRow']['uid'];
+                            } elseif (!empty($formData['parentPageRow']['uid'])) {
+                                $this->viewId = $formData['parentPageRow']['uid'];
+                            }
+                        }
 
-                                // Determine if delete button can be shown
-                                $deleteAccess = false;
-                                if (
-                                    $command === 'edit'
-                                    || $command === 'new'
-                                ) {
-                                    $permission = new Permission($formData['userPermissionOnPage']);
-                                    if ($formData['tableName'] === 'pages') {
-                                        $deleteAccess = $permission->get(Permission::PAGE_DELETE);
-                                    } else {
-                                        $deleteAccess = $permission->get(Permission::CONTENT_EDIT);
-                                    }
-                                }
+                        // Determine if delete button can be shown
+                        $deleteAccess = false;
+                        if (
+                            $command === 'edit'
+                            || $command === 'new'
+                        ) {
+                            $permission = new Permission($formData['userPermissionOnPage']);
+                            if ($formData['tableName'] === 'pages') {
+                                $deleteAccess = $permission->get(Permission::PAGE_DELETE);
+                            } else {
+                                $deleteAccess = $permission->get(Permission::CONTENT_EDIT);
+                            }
+                        }
 
-                                // Display "is-locked" message
-                                if ($command === 'edit') {
-                                    $lockInfo = BackendUtility::isRecordLocked($table, $formData['databaseRow']['uid']);
-                                    if ($lockInfo) {
-                                        $flashMessage = GeneralUtility::makeInstance(
-                                            FlashMessage::class,
-                                            $lockInfo['msg'],
-                                            '',
-                                            FlashMessage::WARNING
-                                        );
-                                        $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
-                                        $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
-                                        $defaultFlashMessageQueue->enqueue($flashMessage);
-                                    }
-                                }
+                        // Display "is-locked" message
+                        if ($command === 'edit') {
+                            $lockInfo = BackendUtility::isRecordLocked($table, $formData['databaseRow']['uid']);
+                            if ($lockInfo) {
+                                $flashMessage = GeneralUtility::makeInstance(
+                                    FlashMessage::class,
+                                    $lockInfo['msg'],
+                                    '',
+                                    FlashMessage::WARNING
+                                );
+                                $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
+                                $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
+                                $defaultFlashMessageQueue->enqueue($flashMessage);
+                            }
+                        }
 
-                                // Record title
-                                if (!$this->storeTitle) {
-                                    $this->storeTitle = htmlspecialchars($this->recTitle ?: ($formData['recordTitle'] ?? ''));
-                                }
+                        // Record title
+                        if (!$this->storeTitle) {
+                            $this->storeTitle = htmlspecialchars($this->recTitle ?: ($formData['recordTitle'] ?? ''));
+                        }
 
-                                $this->elementsData[] = [
-                                    'table' => $table,
-                                    'uid' => $formData['databaseRow']['uid'],
-                                    'pid' => $formData['databaseRow']['pid'],
-                                    'cmd' => $command,
-                                    'deleteAccess' => $deleteAccess
-                                ];
+                        $this->elementsData[] = [
+                            'table' => $table,
+                            'uid' => $formData['databaseRow']['uid'],
+                            'pid' => $formData['databaseRow']['pid'],
+                            'cmd' => $command,
+                            'deleteAccess' => $deleteAccess
+                        ];
 
-                                if ($command !== 'new') {
-                                    BackendUtility::lockRecords($table, $formData['databaseRow']['uid'], $table === 'tt_content' ? $formData['databaseRow']['pid'] : 0);
-                                }
+                        if ($command !== 'new') {
+                            BackendUtility::lockRecords($table, $formData['databaseRow']['uid'], $table === 'tt_content' ? $formData['databaseRow']['pid'] : 0);
+                        }
 
-                                // Set list if only specific fields should be rendered. This will trigger
-                                // ListOfFieldsContainer instead of FullRecordContainer in OuterWrapContainer
-                                if ($this->columnsOnly) {
-                                    if (is_array($this->columnsOnly)) {
-                                        $formData['fieldListToRender'] = $this->columnsOnly[$table];
-                                    } else {
-                                        $formData['fieldListToRender'] = $this->columnsOnly;
-                                    }
-                                }
+                        // Set list if only specific fields should be rendered. This will trigger
+                        // ListOfFieldsContainer instead of FullRecordContainer in OuterWrapContainer
+                        if ($this->columnsOnly) {
+                            if (is_array($this->columnsOnly)) {
+                                $formData['fieldListToRender'] = $this->columnsOnly[$table];
+                            } else {
+                                $formData['fieldListToRender'] = $this->columnsOnly;
+                            }
+                        }
 
-                                $formData['renderType'] = 'outerWrapContainer';
-                                $formResult = $nodeFactory->create($formData)->render();
+                        $formData['renderType'] = 'outerWrapContainer';
+                        $formResult = $nodeFactory->create($formData)->render();
 
-                                $html = $formResult['html'];
+                        $html = $formResult['html'];
 
-                                $formResult['html'] = '';
-                                $formResult['doSaveFieldName'] = 'doSave';
+                        $formResult['html'] = '';
+                        $formResult['doSaveFieldName'] = 'doSave';
 
-                                // @todo: Put all the stuff into FormEngine as final "compiler" class
-                                // @todo: This is done here for now to not rewrite addCssFiles()
-                                // @todo: and printNeededJSFunctions() now
-                                $this->formResultCompiler->mergeResult($formResult);
+                        // @todo: Put all the stuff into FormEngine as final "compiler" class
+                        // @todo: This is done here for now to not rewrite addCssFiles()
+                        // @todo: and printNeededJSFunctions() now
+                        $this->formResultCompiler->mergeResult($formResult);
 
-                                // Seems the pid is set as hidden field (again) at end?!
-                                if ($command === 'new') {
-                                    // @todo: looks ugly
-                                    $html .= LF
-                                        . '<input type="hidden"'
-                                        . ' name="data[' . htmlspecialchars($table) . '][' . htmlspecialchars($formData['databaseRow']['uid']) . '][pid]"'
-                                        . ' value="' . (int)$formData['databaseRow']['pid'] . '" />';
-                                }
+                        // Seems the pid is set as hidden field (again) at end?!
+                        if ($command === 'new') {
+                            // @todo: looks ugly
+                            $html .= LF
+                                . '<input type="hidden"'
+                                . ' name="data[' . htmlspecialchars($table) . '][' . htmlspecialchars($formData['databaseRow']['uid']) . '][pid]"'
+                                . ' value="' . (int)$formData['databaseRow']['pid'] . '" />';
+                        }
 
-                                $editForm .= $html;
-                            } catch (AccessDeniedException $e) {
-                                $this->errorC++;
-                                // Try to fetch error message from "recordInternals" be user object
-                                // @todo: This construct should be logged and localized and de-uglified
-                                $message = (!empty($beUser->errorMsg)) ? $beUser->errorMsg : $e->getMessage() . ' ' . $e->getCode();
-                                $title = $this->getLanguageService()
-                                    ->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noEditPermission');
-                                $editForm .= $this->getInfobox($message, $title);
-                            } catch (DatabaseRecordException | DatabaseRecordWorkspaceDeletePlaceholderException $e) {
-                                $editForm .= $this->getInfobox($e->getMessage());
-                            }
-                        } // End of for each uid
+                        $editForm .= $html;
+                    } catch (AccessDeniedException $e) {
+                        $this->errorC++;
+                        // Try to fetch error message from "recordInternals" be user object
+                        // @todo: This construct should be logged and localized and de-uglified
+                        $message = (!empty($beUser->errorMsg)) ? $beUser->errorMsg : $e->getMessage() . ' ' . $e->getCode();
+                        $title = $this->getLanguageService()
+                            ->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noEditPermission');
+                        $editForm .= $this->getInfobox($message, $title);
+                    } catch (DatabaseRecordException | DatabaseRecordWorkspaceDeletePlaceholderException $e) {
+                        $editForm .= $this->getInfobox($e->getMessage());
                     }
-                }
+                } // End of for each uid
             }
         }
         return $editForm;
@@ -1255,57 +1275,59 @@ class EditDocumentController
      */
     protected function getButtons(ServerRequestInterface $request): void
     {
-        $record = BackendUtility::getRecord($this->firstEl['table'], $this->firstEl['uid']);
-        $TCActrl = $GLOBALS['TCA'][$this->firstEl['table']]['ctrl'];
+        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
 
-        $this->setIsSavedRecord();
+        if ($this->firstEl !== null) {
+            $record = BackendUtility::getRecord($this->firstEl['table'], $this->firstEl['uid']);
+            $TCActrl = $GLOBALS['TCA'][$this->firstEl['table']]['ctrl'];
 
-        $sysLanguageUid = 0;
-        if (
-            $this->isSavedRecord
-            && isset($TCActrl['languageField'], $record[$TCActrl['languageField']])
-        ) {
-            $sysLanguageUid = (int)$record[$TCActrl['languageField']];
-        } elseif (isset($this->defVals['sys_language_uid'])) {
-            $sysLanguageUid = (int)$this->defVals['sys_language_uid'];
-        }
+            $this->setIsSavedRecord();
 
-        $l18nParent = isset($TCActrl['transOrigPointerField'], $record[$TCActrl['transOrigPointerField']])
-            ? (int)$record[$TCActrl['transOrigPointerField']]
-            : 0;
+            $sysLanguageUid = 0;
+            if (
+                $this->isSavedRecord
+                && isset($TCActrl['languageField'], $record[$TCActrl['languageField']])
+            ) {
+                $sysLanguageUid = (int)$record[$TCActrl['languageField']];
+            } elseif (isset($this->defVals['sys_language_uid'])) {
+                $sysLanguageUid = (int)$this->defVals['sys_language_uid'];
+            }
 
-        $this->setIsPageInFreeTranslationMode($record, $sysLanguageUid);
+            $l18nParent = isset($TCActrl['transOrigPointerField'], $record[$TCActrl['transOrigPointerField']])
+                ? (int)$record[$TCActrl['transOrigPointerField']]
+                : 0;
 
-        $buttonBar = $this->moduleTemplate->getDocHeaderComponent()->getButtonBar();
+            $this->setIsPageInFreeTranslationMode($record, $sysLanguageUid);
 
-        $this->registerCloseButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 1);
+            $this->registerCloseButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 1);
 
-        // Show buttons when table is not read-only
-        if (
-            !$this->errorC
-            && !($GLOBALS['TCA'][$this->firstEl['table']]['ctrl']['readOnly'] ?? false)
-        ) {
-            $this->registerSaveButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 2);
-            $this->registerViewButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 3);
-            if ($this->firstEl['cmd'] !== 'new') {
-                $this->registerNewButtonToButtonBar(
-                    $buttonBar,
-                    ButtonBar::BUTTON_POSITION_LEFT,
-                    4,
-                    $sysLanguageUid,
-                    $l18nParent
-                );
-                $this->registerDuplicationButtonToButtonBar(
-                    $buttonBar,
-                    ButtonBar::BUTTON_POSITION_LEFT,
-                    5,
-                    $sysLanguageUid,
-                    $l18nParent
-                );
+            // Show buttons when table is not read-only
+            if (
+                !$this->errorC
+                && !($GLOBALS['TCA'][$this->firstEl['table']]['ctrl']['readOnly'] ?? false)
+            ) {
+                $this->registerSaveButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 2);
+                $this->registerViewButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 3);
+                if ($this->firstEl['cmd'] !== 'new') {
+                    $this->registerNewButtonToButtonBar(
+                        $buttonBar,
+                        ButtonBar::BUTTON_POSITION_LEFT,
+                        4,
+                        $sysLanguageUid,
+                        $l18nParent
+                    );
+                    $this->registerDuplicationButtonToButtonBar(
+                        $buttonBar,
+                        ButtonBar::BUTTON_POSITION_LEFT,
+                        5,
+                        $sysLanguageUid,
+                        $l18nParent
+                    );
+                }
+                $this->registerDeleteButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 6);
+                $this->registerColumnsOnlyButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 7);
+                $this->registerHistoryButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_RIGHT, 1);
             }
-            $this->registerDeleteButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 6);
-            $this->registerColumnsOnlyButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_LEFT, 7);
-            $this->registerHistoryButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_RIGHT, 1);
         }
 
         $this->registerOpenInNewWindowButtonToButtonBar($buttonBar, ButtonBar::BUTTON_POSITION_RIGHT, 2, $request);
diff --git a/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf b/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
index 470fe6186a9ce9b879986851ca0e897857853fe4..39115e4547017a66baa1d668e96c780a7cd21d5a 100644
--- a/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
+++ b/typo3/sysext/backend/Resources/Private/Language/locallang_alt_doc.xlf
@@ -42,6 +42,12 @@
 			<trans-unit id="noDocuments_listmodule" resname="noDocuments_listmodule">
 				<source>the Web&gt;List module</source>
 			</trans-unit>
+			<trans-unit id="noEditForm" resname="noEditForm">
+				<source>Edit form could not be loaded</source>
+			</trans-unit>
+			<trans-unit id="noEditForm.message" resname="noEditForm.message">
+				<source>The edit form could not be loaded for the requested records. This might be due to insufficient permissions.</source>
+			</trans-unit>
 			<trans-unit id="buttons.confirm.duplicate_record_changed.cancel" resname="buttons.confirm.duplicate_record_changed.cancel">
 				<source>Cancel</source>
 			</trans-unit>