Обращение через точку к пустому значению: разбор ошибки и исправление кода
Содержание
Ошибка Значение не является значением объектного типа (Имя) в 1С означает одно: код обратился через точку к свойству значения, у которого свойств нет. Чаще всего это Неопределено или Null, реже строка, число или дата. Слово в скобках — имя свойства, которое код пытался прочитать. Исправление — найти строку, понять, откуда пришло пустое значение, и добавить проверку типа перед обращением.
Типичная ситуация: бухгалтер нажимает «Провести», а вместо проводок видит окно с текстом {Документ.РеализацияТоваровУслуг.МодульОбъекта(214)}: Значение не является значением объектного типа (Склад). Вчера документ проводился. Сегодня в нём пустая строка табличной части или незаполненный реквизит составного типа, и доработанный код на это не рассчитан.
Почему 1С не может прочитать свойство: объектные и примитивные типы
Все значения во встроенном языке 1С делятся на две группы. У одних есть свойства и методы, к ним обращаются через точку. У других свойств нет вообще.
| Группа | Примеры типов | Можно ли писать Значение.Имя |
|---|---|---|
| Примитивные | Строка, Число, Дата, Булево | Нет |
| Особые значения | Неопределено, Null | Нет |
| Ссылки | СправочникСсылка, ДокументСсылка | Да, к реквизитам |
| Объекты и коллекции | ДокументОбъект, Структура, СтрокаТабличнойЧасти | Да |
Когда платформа выполняет Контрагент.ИНН, она сначала смотрит на тип значения в переменной Контрагент. Если там ссылка на справочник — читает реквизит. Если там Неопределено — останавливает выполнение и выводит эту ошибку с именем ИНН в скобках.
💡 Пустая ссылка ведёт себя иначе. У Справочники.Склады.ПустаяСсылка() тип объектный, и чтение реквизита через точку вернёт пустое значение реквизита, а не ошибку. Поэтому сбой почти всегда указывает не на «незаполненный склад», а на значение вообще без типа ссылки.
Как отличить от похожей ошибки
Рядом живёт сообщение Поле объекта не обнаружено (Имя). Их часто путают, хотя причины противоположные.
| Текст ошибки | Что не так | Куда смотреть |
|---|---|---|
Значение не является значением объектного типа (Имя) | В переменной примитив, Неопределено или Null | Откуда пришло значение |
Поле объекта не обнаружено (Имя) | Объект есть, но свойства с таким именем у него нет | Опечатка, переименованный реквизит, ключ структуры |
Где ошибка объектного типа появляется на практике
Источников пустого значения немного, и их стоит знать в лицо. Перечень ниже покрывает большинство случаев в доработанных базах.
- 🔍 Метод поиска ничего не нашёл.
ТабличнаяЧасть.Найти(),Массив.Найти(),ТаблицаЗначений.Найти()возвращаютНеопределено, если совпадения нет. Следующая строкаНайденнаяСтрока.Количествопадает. - 🧩 Реквизит составного типа не заполнен. Пустое значение составного типа — это
Неопределено, а не пустая ссылка. КодОбъект.Основание.Датаработает, пока основание выбрано. - 🗃️ Поле запроса вернуло Null. После левого соединения нет парной записи, и в поле выборки лежит
Null. КодВыборка.Склад.Наименованиеостанавливается. - 📦 Параметр не передали. Функция ждёт ссылку, а её вызвали без параметра, и он получил значение по умолчанию
Неопределено. - 🔤 В переменную записали не тот тип. Например, код из строки файла загрузки вместо найденной по коду ссылки.
ЗначениеЗаполнено()тут вернёт Истина, а ошибка всё равно будет. - 🧱 Структура или соответствие без нужного ключа.
Соответствие.Получить(Ключ)при отсутствии ключа даётНеопределено.
Параметры формы при открытии
Отдельный частый случай — модуль формы в ПриСозданииНаСервере. Форма документа открывается тремя путями: новый документ, копирование и открытие существующего. Параметр Параметры.ЗначениеКопирования заполнен только во втором случае.
Код Параметры.ЗначениеКопирования.Дата работает при копировании и падает при создании нового документа. Перед обращением проверьте параметр через ЗначениеЗаполнено(). То же касается параметров, которые форма получает от вызывающего кода: если её открыли из другого места, параметр может быть не передан.
Ошибка у пользователя в типовой конфигурации
Если программиста нет, а ошибка возникла в типовой БП 3.0, ЗУП 3.1 или УТ 11, сначала проверьте, чей код упал. Нажмите в окне ошибки ссылку с подробностями и посмотрите имя модуля.
- Имя начинается с
ВнешняяОбработкаилиВнешнийОтчет— виновата внешняя обработка или печатная форма. Отключите её и проверьте ещё раз. - В тексте есть имя расширения — откройте
Администрирование → Печатные формы, отчеты и обработки, перейдите к списку расширений и временно снимите флажок активности у подозрительного. - Модуль типовой, доработок нет — обновите конфигурацию до актуального релиза. Если ошибка осталась, передайте полный текст с номером строки на линию поддержки или своему 1С-нику.
Отключение расширения действует для всех пользователей базы. Делайте это в нерабочее время или предупредите коллег: функции расширения пропадут у всех после перезапуска сеанса.
Как найти строку с ошибкой через отладчик
Номер строки в фигурных скобках уже показывает место падения. Но падает строка, где значение прочитали, а испортилось оно раньше. Отладчик помогает пройти путь назад.
Остановка точно в момент ошибки
- Откройте базу в Конфигураторе.
- В меню
ОтладкавыберитеОстановка по ошибке. - Включите флажок остановки и в поле фильтра впишите часть текста:
не является значением объектного типа. Тогда отладчик не будет останавливаться на чужих исключениях внутриПопытка. - Запустите отладку клавишей
F5и повторите действие пользователя. - Выполнение встанет на проблемной строке, а не просто выдаст окно с текстом.
Что проверить в точке остановки
- Наведите курсор на переменную слева от точки или откройте
Отладка → Вычислить выражение(Shift+F9). - Вычислите
ТипЗнч(ИмяПеременной). ОтветНеопределено,NullилиСтрокасразу показывает, какой из сценариев выше ваш. - Откройте стек вызовов (
Ctrl+Alt+C) и поднимитесь на уровень выше. Там видно, кто передал пустое значение. - Добавьте переменную в табло и пройдите код заново по шагам (
F11— с заходом в процедуру,F10— без захода).
💡 Если ошибка возникает в фоновом задании или при обмене, отладчик в пользовательском сеансе её не поймает. Посмотрите полный текст в Администрирование → Обслуживание → Журнал регистрации с отбором по уровню «Ошибка». В событии будет модуль и номер строки.
Отладка на сервере
В клиент-серверной базе серверный код отлаживается, только если на сервере 1С включён режим отладки. Его включает администратор сервера ключом -debug в параметрах службы агента. Перезапуск службы оборвёт сеансы всех пользователей, поэтому это делают вне рабочего времени и чаще на тестовой копии базы.
Защита кода: проверки перед обращением через точку
Задача — проверить значение до точки. Набор приёмов зависит от того, что может прийти.
Результат поиска
НайденнаяСтрока = Объект.Товары.Найти(Номенклатура, "Номенклатура");
Если НайденнаяСтрока = Неопределено Тогда
Количество = 0;
Иначе
Количество = НайденнаяСтрока.Количество;
КонецЕсли;
Сравнение с Неопределено здесь точнее, чем ЗначениеЗаполнено(): строка табличной части с нулевым количеством всё равно найдена.
Ссылка, которая может быть пустой или Null
Если ЗначениеЗаполнено(Склад) Тогда
ИмяСклада = Склад.Наименование;
Иначе
ИмяСклада = "";
КонецЕсли;
ЗначениеЗаполнено() возвращает Ложь для Неопределено, Null и пустой ссылки. Для большинства проверок реквизитов этого достаточно.
Значение, тип которого не гарантирован
Если переменная может содержать строку или ссылку другого вида, ЗначениеЗаполнено() не защитит. Проверяйте тип явно:
Если ТипЗнч(Основание) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
ДатаОснования = Основание.Дата;
Иначе
ДатаОснования = Дата(1, 1, 1);
КонецЕсли;
Для проверки сразу на несколько видов документов подходит Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Основание)).
Чтение одного реквизита
В конфигурациях на БСП (БП 3.0, ЗУП 3.1, УТ 11) есть функция ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН"). Она читает реквизит запросом и не загружает весь объект. Саму ссылку перед вызовом всё равно проверьте на заполненность.
Сравнение способов защиты
| Способ | Когда подходит | Чего не ловит |
|---|---|---|
= Неопределено | Результат Найти(), Получить() | Null, строку вместо ссылки |
ЗначениеЗаполнено() | Реквизиты-ссылки, поля выборки | Значение не того типа |
ТипЗнч() = Тип(...) | Составные типы, внешние данные | Ничего, если перечислены все типы |
Попытка ... Исключение | Внешний код, который нельзя менять | Скрывает причину, замедляет код |
Почему Попытка — не исправление
Оборачивать падающую строку в Попытка хочется, но это прячет симптом. Документ проведётся, а движение по складу запишется с пустым значением. Ошибка всплывёт через месяц в отчёте, и найти её будет сложнее.
Если без исключения не обойтись, хотя бы записывайте причину: ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()) в журнал регистрации через ЗаписьЖурналаРегистрации().
Null в запросах и выборках: где ошибка прячется чаще всего
Язык запросов разыменовывает поля безопасно. Запись Продажи.Контрагент.ИНН в тексте запроса при пустом контрагенте даст NULL, а не ошибку. Ошибка появляется позже — в коде, который обходит выборку.
Пример сбоя
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Товары.Ссылка КАК Номенклатура,
| Остатки.Склад КАК Склад
|ИЗ
| Справочник.Номенклатура КАК Товары
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
| ПО Товары.Ссылка = Остатки.Номенклатура";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Склад.Наименование); // ошибка для товаров без остатков
КонецЦикла;
Товар без остатков попадает в выборку, а Склад у него — Null. На первой такой строке выполнение прервётся с текстом (Наименование) в скобках.
Три способа исправить запрос
- Получить нужное поле в самом запросе. Вместо разыменования в коде добавьте в текст
Остатки.Склад.Наименование КАК СкладНаименование. Пустой склад дастNULL, его легко обработать. - Заменить Null через ЕСТЬNULL. Запись
ЕСТЬNULL(Остатки.Склад, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)) КАК Складвернёт пустую ссылку. Её реквизиты читаются без ошибки. Имя справочника складов возьмите из своей конфигурации. - Уточнить составной тип через ВЫРАЗИТЬ. Для поля вроде
РегистраторилиОснованиеиспользуйтеВЫРАЗИТЬ(Т.Основание КАК Документ.РеализацияТоваровУслуг).Дата. Если тип не совпал, получитеNULLв запросе, а не падение в коде.
Где ещё появляется Null
- 📊 Итоги запроса. В групповых строках после
ИТОГИ ПОполя, по которым не группировали, содержатNull. При обходе сОбходРезультатаЗапроса.ПоГруппировкампроверяйте значение перед точкой. - 🔗 Объединение. При
ОБЪЕДИНИТЬ ВСЕполе, которого нет во второй части, заполняютNULLили пустой ссылкой. Лучше второе — тогда код ниже не придётся защищать. - 🧮 Выгрузка в таблицу значений.
Результат.Выгрузить()переноситNullв колонки как есть. Проверки нужны и при работе с таблицей.
Не разыменовывайте ссылки в цикле по выборке, если можно взять поле в запросе. Каждое Выборка.Склад.Наименование — отдельное обращение к базе. На 10 000 строк это 10 000 лишних запросов, а заодно риск ошибки на каждой строке с Null.
Порядок действий, если ошибка уже мешает работать
Последний пункт важен. Если документ провёлся, откройте его движения и проверьте, что в них нет пустых измерений. Иначе исправление кода оставит в учёте след от старого сбоя.
Частые вопросы
Почему у одного пользователя ошибка есть, а у другого нет?
Ошибка появилась сразу после обновления конфигурации. Что проверить первым?
Поможет ли тестирование и исправление базы?
<Объект не найден>) сами эту ошибку не вызывают: чтение их реквизитов возвращает пустые значения.Можно ли узнать имя переменной, а не только имя свойства?
Ctrl+G и посмотрите, что стоит слева от точки перед этим именем.