Как исправить ошибку «Элемент с установленным признаком "ЭтотУзел" уже существует» при обновлении 1С?

Программист 1С v8.3 (Управляемые формы) 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

Каждый администратор и программист 1С рано или поздно сталкивается с ситуацией, когда стандартное обновление конфигурации прерывается из-за непредвиденных технических сбоев. Одной из таких неприятных и пугающих проблем является ошибка: «Элемент с установленным признаком "ЭтотУзел" уже существует». Чаще всего она возникает при обновлении конфигураций на платформе «1С:Предприятие 8.3» (например, при обновлении «1С:Бухгалтерии предприятия 3.0» на этапе первого запуска информационной базы в режиме «1С:Предприятие», когда процесс аварийно завершается на отметке около 32%).

В этой статье мы подробно разберем природу этого сбоя, выясним, почему в планах обмена внезапно задваиваются предопределенные узлы, а также рассмотрим несколько эффективных практических способов решения проблемы: от простых внешних обработок до официальных инструментов фирмы «1С».

Почему возникает эта ошибка? Выясняем причины

Для начала проанализируем внутренние механизмы платформы «1С:Предприятие 8.3», чтобы понять, как в системе физически могут появиться две записи с уникальным признаком ЭтотУзел в одном плане обмена.

Платформа накладывает жесткое ограничение на уровне СУБД и программного ядра: в любой таблице плана обмена (например, ОбменСообщениями или ОбновлениеИнформационнойБазы) может существовать только одна запись, для которой флаг ЭтотУзел равен Истина. Этот узел идентифицирует текущую информационную базу в распределенной системе.

Однако в процессе обновления могут произойти следующие нежелательные события:

  1. Сбой реструктуризации при изменении режима совместимости. При переходе на новые релизы платформы или конфигурации часто меняется режим совместимости. При реструктуризации таблиц базы данных платформой может быть нарушена внутренняя идентификация предопределенных элементов.
  2. Потеря UUID предопределенного узла. Вследствие некорректной работы платформы уникальный идентификатор (UUID) существующего узла теряется или перезаписывается. В результате системный метод ЭтотУзел() начинает возвращать пустое значение или ссылку на несуществующий объект.
  3. Последствия операции «Тестирование и исправление» (ТиИ). Обнаружив, что обязательный предопределенный узел поврежден или отсутствует, механизм ТиИ принудительно создает новую запись с флагом ЭтотУзел. Однако старый узел (на который завязаны реальные документы, константы и движения в регистрах) никуда не исчезает, а остается в базе в подвешенном состоянии, сохраняя свой старый признак. Так в системе появляются две записи с признаком ЭтотУзел = Истина.
  4. Конфликт при обновлении. При первом запуске базы после обновления конфигурации Библиотека Стандартных Подсистем (БСП) пытается выполнить обработчики обновления, которые обращаются к планам обмена, натыкаются на дубликат и вызывают критический сбой.

Практическое решение №1: Программное исправление дублей через внешнюю обработку

Если мы столкнулись с этой ошибкой, интерактивно удалить или пометить на удаление лишний узел через интерфейс «1С:Предприятие» программа нам не даст — при любой попытке изменения система заблокирует действие и выдаст ту же самую ошибку. В этой ситуации лучшим решением будет написание простой внешней обработки, которая программно снимет признак ЭтотУзел с некорректной записи и позволит её безопасно удалить.

Рассмотрим базовый вариант кода, который используется для обхода элементов плана обмена ОбменСообщениями:


&НаКлиенте
Процедура ВыполнитьОбработку(Команда)
    ВыполнитьОбработкуНаСервере();
КонецПроцедуры

&НаСервере
Процедура ВыполнитьОбработкуНаСервере()
    ВыборкаУзлов = ПланыОбмена.ОбменСообщениями.Выбрать();
    Пока ВыборкаУзлов.Следующий() Цикл
        // Проверяем, что ссылка не совпадает с текущим предопределенным узлом
        Если ВыборкаУзлов.Ссылка <> ПланыОбмена.ОбменСообщениями.ЭтотУзел Тогда
            УзелОбъект = ВыборкаУзлов.ПолучитьОбъект();
            УзелОбъект.ЭтотУзел = Ложь;
            УзелОбъект.Записать();
            Прервать; // Прерываем цикл после обработки первого дубликата
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Важное улучшение кода: обход блокировок и проверок БСП. В типовых конфигурациях при записи объектов планов обмена срабатывают многочисленные проверки и подписки на события БСП. Они могут заблокировать выполнение метода Записать(), посчитав операцию некорректной. Чтобы принудительно записать изменения в базу в обход стандартных проверок платформы, нам обязательно нужно использовать свойство ОбменДанными.Загрузка = Истина.

Модифицируем наш код с учетом этого важного нюанса:


&НаСервере
Процедура ИсправитьДублиУзловНаСервере()
    ВыборкаУзлов = ПланыОбмена.ОбменСообщениями.Выбрать();
    Пока ВыборкаУзлов.Следующий() Цикл
        Если ВыборкаУзлов.Ссылка <> ПланыОбмена.ОбменСообщениями.ЭтотУзел Тогда
            УзелОбъект = ВыборкаУзлов.ПолучитьОбъект();
            
            // Включаем режим загрузки для отключения обработчиков и подписок БСП
            УзелОбъект.ОбменДанными.Загрузка = Истина;
            УзелОбъект.ЭтотУзел = Ложь;
            УзелОбъект.Записать();
            
            // Помечаем объект на удаление для последующей очистки базы
            УзелОбъект.УстановитьПометкуУдаления(Истина);
            УзелОбъект.Записать();
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Разберем еще один сценарий, когда после тестирования и исправления у нас появился дублирующий узел, а старый предопределенный узел потерял свои реквизиты. Мы можем программно переименовать нужный узел, присвоить ему правильный код и удалить все лишние записи. Рассмотрим следующий пример кода:


&НаСервере
Процедура УдалитьЛишниеУзлыНаСервере()
    ВыборкаУзлов = ПланыОбмена.ОбменСообщениями.Выбрать();
    Пока ВыборкаУзлов.Следующий() Цикл
        УзелОбъект = ВыборкаУзлов.ПолучитьОбъект();
        УзелОбъект.ОбменДанными.Загрузка = Истина;
        
        Если ВыборкаУзлов.Ссылка <> ПланыОбмена.ОбменСообщениями.ЭтотУзел Тогда
            // Удаляем некорректный дублирующий узел напрямую из базы
            Попытка
                УзелОбъект.Удалить();
            Исключение
                Сообщить("Не удалось удалить узел напрямую: " + ОписаниеОшибки());
                // В случае неудачного удаления хотя бы помечаем на удаление
                УзелОбъект.УстановитьПометкуУдаления(Истина);
                УзелОбъект.Записать();
            КонецПопытки;
        Иначе
            // Настраиваем корректные реквизиты для правильного предопределенного узла
            УзелОбъект.УстановитьНовыйКод();
            УзелОбъект.Наименование = "Предопределенный обмен";
            Попытка
                УзелОбъект.Записать();
            Исключение
                Сообщить("Ошибка при записи основного узла: " + ОписаниеОшибки());
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Почему простое удаление узла может быть опасным? Задвоение счетов и битые ссылки

Как показывает практика, простое удаление дублирующего узла «в лоб» программным методом не всегда проходит бесследно. Иногда в базе могут задвоиться предопределенные счета в плане счетов или появиться битые ссылки вида <Объект не найден> в различных регистрах сведений и документах.

Это происходит потому, что пока в системе существовало два узла, платформа или фоновые процессы обновления БСП могли записать часть служебной информации с привязкой к «неправильному» узлу. Если мы просто удалим этот узел, то все записи в регистрах, ссылающиеся на него, потеряют связь и превратятся в битые ссылки.

Официальное решение от фирмы «1С» с заменой ссылок

Разработчики «1С» признали существование этой проблемы на уровне платформы и выпустили официальный инструмент для ее безопасного исправления. На портале ИТС опубликована внешняя обработка «Замена ссылок на неправильную запись ЭтотУзел» (имя файла: ReplaceWrongThisNodeReferencesAfterTestAndRepair.epf).

Давайте рассмотрим алгоритм работы этой обработки, который гарантирует полную безопасность ваших данных:

  1. Анализ базы данных. Обработка сканирует таблицы планов обмена и выявляет некорректно созданные дубли.
  2. Сопоставление узлов. Утилита позволяет разработчику вручную или в автоматическом режиме указать, какой из двух узлов является истинным (настоящим предопределенным), а какой — ошибочно созданным дубликатом.
  3. Перенос данных и реквизитов. Все настройки, коды, наименования и табличные части копируются из поврежденного или дублирующего узла в правильный рабочий узел.
  4. Поиск и замена ссылок по всей базе данных. Это ключевой этап. Обработка производит глобальный поиск ссылок на дефектный узел во всех таблицах базы (в константах, справочниках, документах, регистрах сведений, накоплений и бухгалтерии) и корректно заменяет их на ссылку правильного узла. Благодаря этому полностью исключается риск появления битых ссылок и задвоения счетов.
  5. Безопасное удаление. Только после успешной замены всех ссылок обработка окончательно и безопасно удаляет лишний узел-дубликат из информационной базы.

Мы настоятельно рекомендуем использовать именно этот инструмент, если информационная база содержит большой объем учетной информации и на узлы планов обмена завязаны реальные транзакции.

Обратная проблема: когда признак «ЭтотУзел» полностью слетел

Иногда в процессе обновления возникает противоположная ситуация: признак ЭтотУзел полностью слетает с предопределенного узла, и системный метод ЭтотУзел() возвращает пустую ссылку. В этом случае обновление базы аварийно прерывается со следующей ошибкой:
«Ошибка при вызове метода УдалитьРегистрациюИзменений(Выборка.Узел)».

В этот момент обновление зависает, но мы можем запустить внешнюю обработку прямо во время приостановки обновления (через меню Еще -> Открыть внешнюю обработку). Нам необходимо программно принудительно вернуть флаг ЭтотУзел на место.

Проанализируем пример кода для решения этой задачи (на примере плана обмена ОбновлениеИнформационнойБазы):


&НаКлиенте
Процедура ВыполнитьОбработку(Команда)
    ВыполнитьОбработкуНаСервере();
КонецПроцедуры

&НаСервере
Процедура ВыполнитьОбработкуНаСервере()
    // Получаем предопределенный узел через кэшированную функцию БСП
    ПредопределенныйУзел = ОбменДаннымиПовтИсп.ПолучитьЭтотУзелПланаОбмена("ОбновлениеИнформационнойБазы");
    
    Если ЗначениеЗаполнено(ПредопределенныйУзел) Тогда
        ПредопределенныйУзелОб = ПредопределенныйУзел.ПолучитьОбъект();
        
        // Обязательно используем режим загрузки для отключения проверок платформы
        ПредопределенныйУзелОб.ОбменДанными.Загрузка = Истина;
        ПредопределенныйУзелОб.ЭтотУзел = Истина;
        
        Попытка
            ПредопределенныйУзелОб.Записать();
            Сообщить("Признак 'ЭтотУзел' успешно восстановлен!");
        Исключение
            Сообщить("Не удалось записать узел: " + ОписаниеОшибки());
        КонецПопытки;
    Иначе
        Сообщить("Не удалось получить предопределенный узел плана обмена!");
    КонецЕсли;
КонецПроцедуры

После выполнения данной обработки можно перезапустить процесс обновления — ошибка исчезнет, и обновление конфигурации завершится в штатном режиме.

Полезные советы и профилактика

Чтобы минимизировать риски возникновения подобных ошибок в будущем, рекомендуем придерживаться следующих правил при обновлении критически важных баз:

← На главную