Сообщение об ошибке пользователю в 1С 8.3: от Сообщить() до своей формы

· 9 мин

Содержание

Чтобы вывести окно ошибки в 1С, на клиенте вызовите ПоказатьПредупреждение(, "Текст ошибки") — появится модальное по виду окно с кнопкой «ОК». Если нужно не просто показать текст, а прервать операцию и откатить транзакцию, используйте ВызватьИсключение "Текст ошибки"; — платформа сама покажет окно с ошибкой. Для ошибок заполнения, которые надо привязать к полю формы, подходит объект СообщениеПользователю.

Способов вывести сообщение об ошибке в 1С 8.3 шесть, и выбирают их по двум вопросам: где выполняется код (клиент или сервер) и должна ли ошибка остановить выполнение. Всё ниже относится к платформе 8.3 и управляемым формам, а не к конкретной конфигурации: работает одинаково в БП, ЗУП, УТ и в своих разработках.

Какой способ показа ошибки выбрать: сравнение

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

💡 Правило для повседневной разработки: проверка заполнения — СообщениеПользователю, фатальная ошибка в логике — ВызватьИсключение, итог фоновой операции — оповещение, всё, что нужно разбирать потом, — дополнительно в журнал регистрации.

Какая у вас ситуация?

Сообщить() и СообщениеПользователю: вывод ошибки в панель сообщений

Функция Сообщить()

Самый короткий способ вывести текст ошибки:

Сообщить("Не указан контрагент. Документ не записан.");

Сообщение появляется в панели сообщений формы. Вызов работает и на клиенте, и на сервере: серверные сообщения копятся и показываются пользователю, когда управление вернётся на клиент.

Минус — сообщение ни к чему не привязано. Пользователь видит текст, но не понимает, какое поле исправлять. В новых разработках Сообщить() оставляют для быстрой отладки.

Объект СообщениеПользователю

Тот же вывод, но с привязкой к полю формы. Клик по сообщению переводит курсор в нужное поле, а само поле подсвечивается.

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнен контрагент";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.Сообщить();

Если сообщение формируется в модуле объекта, привязку делают через данные:

Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Дата документа не может быть больше текущей";
Сообщение.Поле = "Дата";
Сообщение.УстановитьДанные(ЭтотОбъект);
Сообщение.Сообщить();

В конфигурациях на БСП (а это почти все типовые) есть готовая обёртка, которая делает то же одной строкой и сразу выставляет флаг отказа:

ОбщегоНазначения.СообщитьПользователю("Не заполнен контрагент", ЭтотОбъект, "Контрагент", , Отказ);

На клиенте и в общих модулях клиент-сервер используют ОбщегоНазначенияКлиент.СообщитьПользователю или ОбщегоНазначенияКлиентСервер.СообщитьПользователю.

Отказ от записи вместе с сообщением

Само сообщение ничего не останавливает. Чтобы документ не записался, в обработчике нужно выставить параметр Отказ:

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

Платформа сама добавит общее окно «Не удалось записать…», а список причин окажется в панели сообщений.

Окно предупреждения: ПоказатьПредупреждение() и ПоказатьВопрос()

Когда нужно именно окно поверх формы, а не строка внизу, используют ПоказатьПредупреждение(). Метод работает только на клиенте.

&НаКлиенте
Процедура ПроверитьИВыполнить(Команда)
	Если Не ЗначениеЗаполнено(Объект.Склад) Тогда
		ПоказатьПредупреждение(, "Выберите склад перед заполнением табличной части.", , "Ошибка заполнения");
		Возврат;
	КонецЕсли;
	ЗаполнитьНаСервере();
КонецПроцедуры

Параметры по порядку: описание оповещения о закрытии, текст, таймаут в секундах, заголовок окна. Окно блокирует интерфейс, но код после вызова не ждёт нажатия «ОК». Поэтому в примере стоит Возврат.

Если после закрытия окна нужно что-то сделать, передайте ОписаниеОповещения:

&НаКлиенте
Процедура ПоказатьОшибкуИЗакрыть()
	Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияПредупреждения", ЭтотОбъект);
	ПоказатьПредупреждение(Оповещение, "Документ заблокирован другим пользователем.");
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗакрытияПредупреждения(ДополнительныеПараметры) Экспорт
	Закрыть();
КонецПроцедуры

Когда у ошибки есть варианты действий («Повторить» / «Отмена»), подходит ПоказатьВопрос() с режимом РежимДиалогаВопрос.ПовторитьОтмена или РежимДиалогаВопрос.ДаНет. Ответ приходит в процедуру оповещения как значение КодВозвратаДиалога.

Почему старый Предупреждение() выдаёт ошибку

Синхронные Предупреждение() и Вопрос() — модальные. В свойствах корня конфигурации есть «Режим использования модальности». Если там стоит «Не использовать» (так в новых конфигурациях и во всех типовых), вызов падает с текстом:

Использование модальных окон в данном режиме запрещено!

Не переключайте режим модальности в типовой конфигурации ради одного окна: модальные окна не работают в веб-клиенте на части браузеров и в мобильном клиенте, а правка свойства снимает конфигурацию с полной поддержки. Перепишите вызов на ПоказатьПредупреждение().

ВызватьИсключение: окно ошибки с остановкой выполнения

ВызватьИсключение прерывает выполнение кода. Если исключение никто не перехватил, пользователь видит стандартное окно ошибки с вашим текстом, а открытая транзакция откатывается.

Если Остаток < Количество Тогда
	ВызватьИсключение "Недостаточно товара на складе. Остаток: " + Формат(Остаток, "ЧГ=0");
КонецЕсли;

Это единственный способ из списка, который гарантированно не даст коду пойти дальше. Его ставят там, где продолжение приведёт к неверным данным: в проведении, в обработке обмена, в расчёте.

Перехват и повторный выброс

Исключение можно поймать, записать подробности и показать пользователю короткий текст:

Попытка
	ВыполнитьРасчет();
Исключение
	Инфо = ИнформацияОбОшибке();
	ЗаписьЖурналаРегистрации("Расчет.Ошибка", УровеньЖурналаРегистрации.Ошибка, , ,
		ПодробноеПредставлениеОшибки(Инфо));
	ВызватьИсключение "Расчёт не выполнен: " + КраткоеПредставлениеОшибки(Инфо);
КонецПопытки;

Что есть для разбора ошибки:

  • 🔹 ОписаниеОшибки() — текст ошибки одной строкой;
  • 🔹 ИнформацияОбОшибке() — объект со свойствами Описание, ИмяМодуля, НомерСтроки, ИсходнаяСтрока, Причина;
  • 🔹 КраткоеПредставлениеОшибки() — текст для пользователя, без технических подробностей;
  • 🔹 ПодробноеПредставлениеОшибки() — текст со стеком вызовов, для журнала.

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

ВызватьИсключение; без текста внутри блока Исключение пробрасывает ту же ошибку дальше, сохраняя исходную информацию.

Пустой блок Исключение … КонецПопытки — худший вариант. Ошибка исчезает: окна нет, в журнале пусто, данные могут остаться наполовину записанными. Хотя бы пишите её в журнал регистрации.

Всплывающее оповещение вместо модального окна

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

&НаКлиенте
Процедура ПослеВыгрузки(Результат, ДополнительныеПараметры) Экспорт
	Если Не Результат.Успешно Тогда
		ПоказатьОповещениеПользователя("Выгрузка не выполнена",
			ПолучитьНавигационнуюСсылку(Объект.Ссылка),
			Результат.ТекстОшибки, , СтатусОповещенияПользователя.Важное);
	КонецЕсли;
КонецПроцедуры

Параметры: заголовок, действие при нажатии (навигационная ссылка или ОписаниеОповещения), пояснение, картинка, статус, ключ уникальности. Со статусом Важное оповещение остаётся в центре оповещений, и пользователь найдёт его позже.

Когда оповещение уместно, а когда нет:

  • ✅ результат фонового задания или пакетной обработки;
  • ✅ неудачная отправка в ЭДО или по почте, если пользователь уже ушёл в другое окно;
  • ❌ ошибка, после которой нельзя продолжать: уведомление легко не заметить.

Запись ошибки в журнал регистрации

Журнал регистрации — не способ показать ошибку, а способ её сохранить. Пользователь закрыл окно и забыл текст, а администратор найдёт запись с временем, пользователем и стеком.

ЗаписьЖурналаРегистрации("Обмен.ЗагрузкаКонтрагентов",
	УровеньЖурналаРегистрации.Ошибка,
	Метаданные.Справочники.Контрагенты,
	СсылкаНаКонтрагента,
	ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));

Имя события лучше строить иерархически, через точку: по нему потом фильтруют журнал.

Где смотреть записи:

  1. В пользовательском режиме типовых конфигураций — раздел Администрирование → Обслуживание, группа отчётов администратора, ссылка «Журнал регистрации».
  2. В любой базе — Функции для технического специалиста → Стандартные → Журнал регистрации (команда «Функции для технического специалиста» включается в параметрах программы).
  3. В конфигураторе — Администрирование → Журнал регистрации.

В журнале поставьте отбор по уровню «Ошибка» и по имени события — так вы отсечёте тысячи служебных записей.

Своя форма для вывода ошибки

Стандартного окна мало, если ошибок несколько, нужен длинный текст с прокруткой или кнопка «Скопировать для поддержки». Тогда делают общую форму.

Пошагово:

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

Режим БлокироватьОкноВладельца даёт поведение модального окна без нарушения режима модальности. Для типовой конфигурации форму добавляют в расширение, чтобы не снимать основную конфигурацию с поддержки.

Вывод ошибок в разных режимах запуска

Один и тот же код ведёт себя по-разному в зависимости от того, кто и как его вызвал.

КонтекстЧто увидит пользовательЧто делать
Тонкий и веб-клиент, управляемые формывсё, что описано вышеасинхронные методы Показать…
Толстый клиент, обычное приложениеработают и модальные Предупреждение(), Вопрос()в новом коде всё равно лучше асинхронные
Серверный вызов из формысообщения доходят после возврата на клиентокна открывайте на клиенте по результату вызова
Фоновое заданиеничего, пока форма сама не заберёт сообщенияФоновоеЗадание.ПолучитьСообщенияПользователю()
Регламентное заданиеникого неттолько журнал регистрации
HTTP-сервис, веб-сервис, COM-соединениеокон неттекст ошибки в ответе + журнал

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

&НаКлиенте
Процедура Загрузить(Команда)
	ТекстОшибки = ЗагрузитьНаСервере();
	Если ЗначениеЗаполнено(ТекстОшибки) Тогда
		ПоказатьПредупреждение(, ТекстОшибки, , "Загрузка не выполнена");
	КонецЕсли;
КонецПроцедуры

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

Ошибки при выводе сообщений, которые встречаются в коде

Разработчики чаще всего спотыкаются на этом:

  • ⚠️ Код после ПоказатьПредупреждение() выполняется сразу. Ждут, что он остановится, как старый Предупреждение(). Нужен Возврат или продолжение в процедуре оповещения.
  • ⚠️ Сообщение есть, а отказа нет. СообщениеПользователю выведено, Отказ не выставлен — документ записывается с ошибкой.
  • ⚠️ Неверный путь в Поле. В модуле формы пишут "Объект.Контрагент", а в модуле объекта — просто "Контрагент" вместе с УстановитьДанные. Перепутали — сообщение выводится, но к полю не переходит.
  • ⚠️ Склейка числа со строкой без формата. "Остаток: " + Остаток даст «1 250» с разделителем групп разрядов, а в коде, номерах и ссылках это лишний пробел. Используйте Формат(Остаток, "ЧГ=0") или СтрШаблон().
  • ⚠️ Технический текст пользователю. Бухгалтеру ПодробноеПредставлениеОшибки со стеком не поможет. Ему — короткий текст, стек — в журнал.
  • ⚠️ Сообщения в цикле. Тысяча строк в панели сообщений равна ни одной. Соберите ошибки в массив и выведите сводку или откройте свою форму со списком.
Как вывести ошибку с переносом строки?
Используйте Символы.ПС между частями текста: "Строка 1" + Символы.ПС + "Строка 2". Работает во всех способах показа.
Можно ли закрыть окно предупреждения автоматически?
Да. Третий параметр ПоказатьПредупреждение() — таймаут в секундах. По его истечении окно закроется само, а процедура оповещения всё равно вызовется.
Как очистить панель сообщений перед новой проверкой?
Вызовите ОчиститьСообщения() на клиенте. Иначе пользователь увидит вперемешку старые и новые ошибки.
Откатывается ли транзакция при ВызватьИсключение внутри Попытки?
Если вы перехватили исключение внутри открытой транзакции, она становится непригодной для фиксации. Её нужно отменить через ОтменитьТранзакцию(), а не пытаться продолжить запись.
Как показать ошибку на английском, если у пользователя другой язык?
Используйте НСтр("ru = 'Не заполнен контрагент'; en = 'Counterparty is not filled'"). Платформа выберет строку по языку пользователя.