«В данной транзакции уже происходили ошибки» в 1С: причины и решение
Внутри транзакции уже произошло исключение, транзакция помечена как ошибочная, а код продолжил работать с базой. Любая следующая операция с данными в такой транзакции выдаёт это сообщение.
Текст ошибки
Причины
- Исключение внутри транзакции перехвачено через Попытка...Исключение и проигнорировано
- Ошибка в обработчике подписки или модуле объекта при записи, после которой код продолжил запись других объектов
- Попытка записать объект после отказа в обработчике ПередЗаписью внутри общей транзакции
- Ошибка в типовом механизме при проведении, замаскированная доработкой
Почему так происходит
Платформа откатывает изменения транзакции целиком. Если внутри транзакции что-то сломалось, зафиксировать её уже нельзя, даже если исключение было перехвачено. Поэтому настоящая причина — первая ошибка, а «В данной транзакции уже происходили ошибки» лишь следствие.
Как найти первую ошибку
- Откройте журнал регистрации и отберите события с уровнем «Ошибка» на время сбоя. Первая запись в серии обычно и есть причина.
- В конфигураторе включите остановку по ошибке: «Отладка» → «Остановка по ошибке», без фильтра по тексту. Отладчик остановится на первом исключении, даже если оно перехвачено.
- Посмотрите обработчики, которые выполняются в той же транзакции:
ПередЗаписью,ПриЗаписи,ОбработкаПроведения, подписки на события, расширения.
Правильный шаблон транзакции
Если исключение внутри транзакции перехвачено, транзакцию нужно отменить и, как правило, пробросить исключение дальше:
НачатьТранзакцию();
Попытка
ЗаписатьШапку(Данные);
ЗаписатьТовары(Данные);
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("Загрузка данных", УровеньЖурналаРегистрации.Ошибка,,,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
Чего делать нельзя
НачатьТранзакцию();
Для Каждого Элемент Из Список Цикл
Попытка
Элемент.ПолучитьОбъект().Записать();
Исключение
// ошибка проглочена, цикл продолжается -
// следующая запись выдаст «уже происходили ошибки»
КонецПопытки;
КонецЦикла;
ЗафиксироватьТранзакцию();
Если нужно записать как можно больше объектов, пропуская проблемные, используйте отдельную транзакцию на каждый объект, а не одну общую.
Отказ вместо исключения
В обработчиках ПередЗаписью и ОбработкаПроверкиЗаполнения для отказа от записи используйте параметр Отказ = Истина и сообщение пользователю. Тогда вызывающий код получит понятную ошибку записи, а не цепочку исключений.
Для пользователя
Ошибка почти всегда указывает на проблему в коде или в данных, которые обрабатываются одной операцией. Повторите действие для одного документа, чтобы найти проблемный объект, и передайте администратору время сбоя для поиска в журнале регистрации.
Если ошибка появляется при групповом перепроведении или загрузке данных, запустите операцию на меньшем периоде или для меньшего числа объектов. Так проще найти документ, на котором возникает первая ошибка, и исправить именно его.
Частые вопросы
Можно ли просто убрать Попытку?
Тогда исключение дойдёт до пользователя с настоящей причиной, и разбираться станет проще. Но правильнее оставить перехват с ОтменитьТранзакцию() и ВызватьИсключение, чтобы сохранить запись в журнал.
Транзакцию я не открывал. Откуда она?
Платформа сама открывает транзакцию при записи и проведении объекта. Всё, что выполняется в обработчиках записи и подписках, идёт внутри неё.