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

· 9 мин

Содержание

Ошибка Значение не является значением объектного типа (Имя) в 1С означает одно: код обратился через точку к свойству значения, у которого свойств нет. Чаще всего это Неопределено или Null, реже строка, число или дата. Слово в скобках — имя свойства, которое код пытался прочитать. Исправление — найти строку, понять, откуда пришло пустое значение, и добавить проверку типа перед обращением.

Типичная ситуация: бухгалтер нажимает «Провести», а вместо проводок видит окно с текстом {Документ.РеализацияТоваровУслуг.МодульОбъекта(214)}: Значение не является значением объектного типа (Склад). Вчера документ проводился. Сегодня в нём пустая строка табличной части или незаполненный реквизит составного типа, и доработанный код на это не рассчитан.

Почему 1С не может прочитать свойство: объектные и примитивные типы

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

ГруппаПримеры типовМожно ли писать Значение.Имя
ПримитивныеСтрока, Число, Дата, БулевоНет
Особые значенияНеопределено, NullНет
СсылкиСправочникСсылка, ДокументСсылкаДа, к реквизитам
Объекты и коллекцииДокументОбъект, Структура, СтрокаТабличнойЧастиДа

Когда платформа выполняет Контрагент.ИНН, она сначала смотрит на тип значения в переменной Контрагент. Если там ссылка на справочник — читает реквизит. Если там Неопределено — останавливает выполнение и выводит эту ошибку с именем ИНН в скобках.

💡 Пустая ссылка ведёт себя иначе. У Справочники.Склады.ПустаяСсылка() тип объектный, и чтение реквизита через точку вернёт пустое значение реквизита, а не ошибку. Поэтому сбой почти всегда указывает не на «незаполненный склад», а на значение вообще без типа ссылки.

Как отличить от похожей ошибки

Рядом живёт сообщение Поле объекта не обнаружено (Имя). Их часто путают, хотя причины противоположные.

Текст ошибкиЧто не такКуда смотреть
Значение не является значением объектного типа (Имя)В переменной примитив, Неопределено или NullОткуда пришло значение
Поле объекта не обнаружено (Имя)Объект есть, но свойства с таким именем у него нетОпечатка, переименованный реквизит, ключ структуры

Где ошибка объектного типа появляется на практике

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

  • 🔍 Метод поиска ничего не нашёл. ТабличнаяЧасть.Найти(), Массив.Найти(), ТаблицаЗначений.Найти() возвращают Неопределено, если совпадения нет. Следующая строка НайденнаяСтрока.Количество падает.
  • 🧩 Реквизит составного типа не заполнен. Пустое значение составного типа — это Неопределено, а не пустая ссылка. Код Объект.Основание.Дата работает, пока основание выбрано.
  • 🗃️ Поле запроса вернуло Null. После левого соединения нет парной записи, и в поле выборки лежит Null. Код Выборка.Склад.Наименование останавливается.
  • 📦 Параметр не передали. Функция ждёт ссылку, а её вызвали без параметра, и он получил значение по умолчанию Неопределено.
  • 🔤 В переменную записали не тот тип. Например, код из строки файла загрузки вместо найденной по коду ссылки. ЗначениеЗаполнено() тут вернёт Истина, а ошибка всё равно будет.
  • 🧱 Структура или соответствие без нужного ключа. Соответствие.Получить(Ключ) при отсутствии ключа даёт Неопределено.

Параметры формы при открытии

Отдельный частый случай — модуль формы в ПриСозданииНаСервере. Форма документа открывается тремя путями: новый документ, копирование и открытие существующего. Параметр Параметры.ЗначениеКопирования заполнен только во втором случае.

Код Параметры.ЗначениеКопирования.Дата работает при копировании и падает при создании нового документа. Перед обращением проверьте параметр через ЗначениеЗаполнено(). То же касается параметров, которые форма получает от вызывающего кода: если её открыли из другого места, параметр может быть не передан.

Ошибка у пользователя в типовой конфигурации

Если программиста нет, а ошибка возникла в типовой БП 3.0, ЗУП 3.1 или УТ 11, сначала проверьте, чей код упал. Нажмите в окне ошибки ссылку с подробностями и посмотрите имя модуля.

  1. Имя начинается с ВнешняяОбработка или ВнешнийОтчет — виновата внешняя обработка или печатная форма. Отключите её и проверьте ещё раз.
  2. В тексте есть имя расширения — откройте Администрирование → Печатные формы, отчеты и обработки, перейдите к списку расширений и временно снимите флажок активности у подозрительного.
  3. Модуль типовой, доработок нет — обновите конфигурацию до актуального релиза. Если ошибка осталась, передайте полный текст с номером строки на линию поддержки или своему 1С-нику.

Отключение расширения действует для всех пользователей базы. Делайте это в нерабочее время или предупредите коллег: функции расширения пропадут у всех после перезапуска сеанса.

Как найти строку с ошибкой через отладчик

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

Остановка точно в момент ошибки

  1. Откройте базу в Конфигураторе.
  2. В меню Отладка выберите Остановка по ошибке.
  3. Включите флажок остановки и в поле фильтра впишите часть текста: не является значением объектного типа. Тогда отладчик не будет останавливаться на чужих исключениях внутри Попытка.
  4. Запустите отладку клавишей F5 и повторите действие пользователя.
  5. Выполнение встанет на проблемной строке, а не просто выдаст окно с текстом.

Что проверить в точке остановки

  • Наведите курсор на переменную слева от точки или откройте Отладка → Вычислить выражение (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. На первой такой строке выполнение прервётся с текстом (Наименование) в скобках.

Три способа исправить запрос

  1. Получить нужное поле в самом запросе. Вместо разыменования в коде добавьте в текст Остатки.Склад.Наименование КАК СкладНаименование. Пустой склад даст NULL, его легко обработать.
  2. Заменить Null через ЕСТЬNULL. Запись ЕСТЬNULL(Остатки.Склад, ЗНАЧЕНИЕ(Справочник.Склады.ПустаяСсылка)) КАК Склад вернёт пустую ссылку. Её реквизиты читаются без ошибки. Имя справочника складов возьмите из своей конфигурации.
  3. Уточнить составной тип через ВЫРАЗИТЬ. Для поля вроде Регистратор или Основание используйте ВЫРАЗИТЬ(Т.Основание КАК Документ.РеализацияТоваровУслуг).Дата. Если тип не совпал, получите NULL в запросе, а не падение в коде.

Где ещё появляется Null

  • 📊 Итоги запроса. В групповых строках после ИТОГИ ПО поля, по которым не группировали, содержат Null. При обходе с ОбходРезультатаЗапроса.ПоГруппировкам проверяйте значение перед точкой.
  • 🔗 Объединение. При ОБЪЕДИНИТЬ ВСЕ поле, которого нет во второй части, заполняют NULL или пустой ссылкой. Лучше второе — тогда код ниже не придётся защищать.
  • 🧮 Выгрузка в таблицу значений. Результат.Выгрузить() переносит Null в колонки как есть. Проверки нужны и при работе с таблицей.

Не разыменовывайте ссылки в цикле по выборке, если можно взять поле в запросе. Каждое Выборка.Склад.Наименование — отдельное обращение к базе. На 10 000 строк это 10 000 лишних запросов, а заодно риск ошибки на каждой строке с Null.

Порядок действий, если ошибка уже мешает работать

Разбор ошибки объектного типа
Выполнено: 0 / 7

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

Частые вопросы

Почему у одного пользователя ошибка есть, а у другого нет?
Код один, а данные разные. Ошибку обычно вызывает конкретный документ или строка: незаполненный реквизит, товар без остатка, контрагент без договора. Попросите пользователя назвать документ и откройте его сами.
Ошибка появилась сразу после обновления конфигурации. Что проверить первым?
Расширения и внешние печатные формы. Они рассчитаны на старую структуру: реквизит могли переименовать или сделать составным. Отключите доработку и повторите действие — если ошибка ушла, доработку нужно адаптировать к новому релизу.
Поможет ли тестирование и исправление базы?
Как правило, нет. Ошибка возникает в коде, а не в повреждённых данных. Битые ссылки (<Объект не найден>) сами эту ошибку не вызывают: чтение их реквизитов возвращает пустые значения.
Можно ли узнать имя переменной, а не только имя свойства?
Текст ошибки содержит только имя свойства. Переменную показывает номер строки в модуле: откройте модуль, перейдите к строке через Ctrl+G и посмотрите, что стоит слева от точки перед этим именем.
Что делать, если модуль в ошибке закрыт паролем?
Код такой поставки не изменить без разработчика. Передайте ему полный текст ошибки, номер строки и шаги воспроизведения. Временно можно отключить эту обработку или расширение, если без них базой можно пользоваться.