Как передать текст ошибки из ВызватьИсключение на клиент при записи документа в 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

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

Почему ОписаниеОшибки() возвращает пустую строку на клиенте

Для начала проанализируем ситуацию, описанную в теме. Разработчик пытается обернуть вызов системного метода Форма.Записать() в блок Попытка...Исключение на клиенте:


Попытка
    Результат = Форма.Записать(ПараметрыЗаписи);
Исключение
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ОписаниеОшибки());
    Результат = Ложь;
КонецПопытки;

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

  1. Очистка контекста при переходе между сервером и клиентом. Метод формы Записать() выполняет сложную последовательность действий, включающую серверные вызовы. Если на сервере происходит аварийное завершение транзакции из-за оператора ВызватьИсключение, платформа прерывает выполнение серверного вызова и возвращает на клиент общую ошибку выполнения метода. Исходный стек исключений СУБД при этом часто очищается, чтобы избежать передачи сырых системных данных на сторону клиента.
  2. Откат транзакции и очистка очереди сообщений. При аварийном прерывании транзакции (Rollback) платформа 1С сбрасывает все временные буферы сообщений. Если сообщение об ошибке не было должным образом зарегистрировано в специальной очереди платформы, оно просто уничтожается вместе с откатом транзакции СУБД.
  3. Особенность работы отладчика. Это критически важный нюанс: если вы остановились точкой останова в блоке Исключение и попытались вычислить выражение ОписаниеОшибки() через Табло или форму «Вычислить выражение», платформа вернет пустую строку! Сам факт обращения отладчика к контексту исполнения сбивает указатель на последнее зарегистрированное исключение. Для корректной отладки всегда необходимо присваивать результат функции локальной переменной в первой же строке блока: ТекстОшибки = ОписаниеОшибки();.

Проблема «сломанной транзакции» (Broken Transaction)

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

  1. Вызывается метод Форма.Записать().
  2. В транзакции начинается проведение документа.
  3. Записывается набор записей регистра РасчетыСКлиентами.
  4. В обработчике события ПриЗаписи этого регистра вызывается запись другого набора — РасчетыСКлиентамиПоСрокам.
  5. В обработчике ПриЗаписи второго регистра срабатывает проверка даты запрета изменения, которая вызывает оператор ВызватьИсключение.

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

Решение 1. Переход на стандартный механизм «Отказ = Истина» и вывод сообщений

Использование оператора ВызватьИсключение внутри транзакционных обработчиков (таких как ПередЗаписью, ПриЗаписи, ОбработкаПроведения) для вывода бизнес-предупреждений категорически противоречит стандартам разработки фирмы «1С». Исключения должны использоваться только для обработки непредвиденных аппаратных или системных сбоев (например, отсутствие связи с базой данных).

Для штатных бизнес-проверок мы должны использовать установку параметра Отказ = Истина в сочетании с выводом сообщений в специализированную очередь платформы через модуль ОбщегоНазначенияКлиентСервер. Перепишем проблемный участок кода в модуле набора записей регистра:


// Вместо ВызватьИсключение ОписаниеОшибки;
Если ДатыЗапретаИзменения.НайденЗапретИзмененияДанных(ДанныеДляПроверки, ЭтотОбъект) Тогда
    Отказ = Истина;
    
    // Формируем понятный текст для пользователя
    ТекстСообщения = НСтр("ru = 'Изменяемые данные взаиморасчетов находятся в закрытом периоде.'");
    
    // Регистрируем сообщение в очереди платформы
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
КонецЕсли;

Как это работает:

Решение 2. Предварительная проверка перед транзакцией

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

Для этого в модуле формы документа перед вызовом записи добавим вызов серверной проверки:


&НаКлиенте
Процедура ПередЗаписью(Отказ, ПараметрыЗаписи)
    
    // Выполняем интерактивную проверку даты запрета на сервере
    Если ПроверитьДатуЗапретаНаСервере() Тогда
        Отказ = Истина;
        Возврат;
    КонецЕсли;
    
КонецПроцедуры

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

Этот подход гарантирует, что пользователь вообще не зайдет в транзакцию записи, если данные некорректны. Это экономит ресурсы сервера СУБД и исключает появление нечитаемых системных ошибок. Для отслеживания порядка срабатывания процедур при записи объектов пригодится инструмент для изучения последовательности событий 1С.

Использование современных механизмов БСП для анализа исключений

Если вы все же вынуждены работать с перехватом исключений в нетиповом коде (например, при интеграции со сторонними сервисами или чтении внешних файлов) на платформе версии 8.3.17 и выше, настоятельно рекомендуется отказаться от использования устаревшей функции ОписаниеОшибки().

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


Попытка
    // Какой-то небезопасный код обработки данных
    ИнтеграцияССервисомСервер.ОтправитьДанные(Объект.Ссылка);
Исключение
    // Получаем структурированную информацию об ошибке
    ИнформацияОбОшибке = ИнформацияОбОшибке();
    
    // Формируем понятный текст для пользователя (без технических деталей)
    ТекстДляПользователя = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке);
    ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстДляПользователя);
    
    // Записываем детальную техническую информацию со стеком вызовов в Журнал регистрации
    ЗаписатьВЖурналРегистрации(
        "Интеграция",
        УровеньЖурналаРегистрации.Ошибка,
        ,
        ,
        ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке)
    );
КонецПопытки;

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

Резюме и рекомендации

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

← На главную