Обращение через точку к Неопределено или Null: как найти и устранить причину
Содержание
Ошибка Значение не является значением объектного типа (Контрагент) значит одно: код обратился через точку к значению, у которого нет свойств. Чаще всего это Неопределено или Null, реже число, строка или дата. Слово в скобках — имя свойства или метода, которое программа пыталась прочитать. Исправление — найти строку, где переменная оказалась пустой, и добавить проверку или устранить источник пустого значения.
Частое заблуждение — считать, что «сломалась база» и нужно тестирование и исправление. Почти всегда база в порядке, а ошибка в коде конфигурации, расширения или внешней обработки. ТиИ здесь помогает только в одном случае: когда в данных есть битые ссылки, и код спотыкается именно о них.
Как читать текст ошибки и что он сообщает
Полное сообщение платформы выглядит примерно так:
{ОбщийМодуль.ОбменСКассой.Модуль(214)}: Ошибка при вызове метода контекста (Записать)
Объект.Контрагент.ИНН
по причине:
Значение не является значением объектного типа (ИНН)
В нём три полезные части:
- 📍 Модуль и номер строки в фигурных скобках — точное место сбоя. Это первое, что нужно разработчику.
- 🔤 Выражение — строка кода, на которой всё упало. Видно, что вычислялась цепочка
Объект.Контрагент.ИНН. - 🔑 Имя в скобках после текста ошибки — свойство, до которого не дошли. Если в скобках
ИНН, значит, пустым оказалсяОбъект.Контрагент, а не самОбъект.
Правило простое: пустое значение стоит слева от того имени, что указано в скобках. Если в цепочке Документ.Основание.Договор.Владелец ошибка жалуется на Владелец, проверять нужно Документ.Основание.Договор.
Пользователю без доступа к Конфигуратору достаточно нажать «Подробно» в окне ошибки и скопировать весь текст. По нему разработчик найдёт строку за минуту, а по скриншоту «выскочила ошибка» — нет.
Какие типы бывают «необъектными»
| Значение | Откуда берётся | Можно ли обращаться через точку |
|---|---|---|
Неопределено | функция без Возврат, не найденная строка, не переданный параметр | нет |
Null | левое соединение в запросе, пустое поле составного типа в выборке | нет |
| Число, строка, дата, булево | поле составного типа, ошибка в присваивании | нет |
| Пустая ссылка | незаполненный реквизит справочника или документа | да, реквизиты вернутся пустыми |
| Структура, соответствие | параметры, JSON, настройки | да, но по ключам |
Пустая ссылка через точку читается без этой ошибки: платформа вернёт пустые значения реквизитов. Поэтому проблема почти всегда в Неопределено или Null.
Почему пустыми оказываются параметры процедур и функций
Значительная часть случаев связана с параметрами: процедура ждёт ссылку, а получает Неопределено. Типичные причины:
- 🔁 Функция не дошла до
Возврат. Если в одной из веток условияВозвратзабыли, вызывающий код получитНеопределено. - 🔍 Поиск ничего не нашёл.
ТаблицаЗначений.Найти()иКоллекция.Найти()возвращаютНеопределено, если совпадения нет. АНайтиСтроки()возвращает массив, и обращение к нему через точку тоже даст ошибку. - 📋 Нет текущей строки.
Элементы.Товары.ТекущиеДанныеравноНеопределено, когда в таблице ничего не выделено или она пустая. Пользователь нажал кнопку на пустом списке — и получил ошибку. - 🪟 Форму открыли без нужного параметра. Код
Параметры.Основание.Контрагентупадёт, если форму открыли не «на основании», а из списка. - 🧩 Необязательный параметр со значением по умолчанию.
Процедура Заполнить(Склад = Неопределено)— и внутри сразуСклад.Подразделение. - 🗂️
ПолучитьОбъект()вернулНеопределено. Так бывает у пустой ссылки и у ссылки на удалённый объект. Следующая строкаОбъект.Записать()падает.
Пример с ошибкой и исправлением
Код, который выдаёт ошибку на пустой таблице:
&НаКлиенте
Процедура ПодобратьЦену(Команда)
Номенклатура = Элементы.Товары.ТекущиеДанные.Номенклатура;
ПодобратьЦенуНаСервере(Номенклатура);
КонецПроцедуры
Исправленный вариант:
&НаКлиенте
Процедура ПодобратьЦену(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
ПоказатьПредупреждение(, "Выберите строку в таблице товаров.");
Возврат;
КонецЕсли;
ПодобратьЦенуНаСервере(ТекущиеДанные.Номенклатура);
КонецПроцедуры
Пользователь получает понятное сообщение вместо системной ошибки, а сам код больше не падает.
Диагностика ошибки «Значение не является значением объектного типа» по шагам
Если строка из текста ошибки сразу не объясняет причину, действуйте по порядку.
Шаг 1. Повторите ошибку осознанно
Запишите, на каком документе, кнопке и данных она возникает. Ошибка «на всех документах» и «только на одном» — это разные причины. Во втором случае смотрите данные: незаполненный реквизит, удалённый контрагент, строка без номенклатуры.
Шаг 2. Проверьте, чей это код
Модуль в фигурных скобках подскажет источник:
ОбщийМодуль,Документ,Справочникбез префикса — код типовой или доработанной конфигурации;- имя с префиксом расширения или пометкой расширения — код расширения;
ВнешняяОбработкаилиВнешнийОтчет— подключённая внешняя обработка.
Для типовой конфигурации без доработок первым делом обновите её до актуального релиза: подобные ошибки исправляют в обновлениях. Для расширения временно отключите его в Администрирование → Печатные формы, отчеты и обработки → Расширения (снимите флажок «Активно») и перезапустите сеанс. Если ошибка ушла — виновато расширение.
Шаг 3. Включите остановку по ошибке
В Конфигураторе запустите отладку (Отладка → Начать отладку → Тонкий клиент или клавиша F5). Затем включите Отладка → Остановка по ошибке и отметьте флажок остановки по любой ошибке. Повторите действие пользователя. Отладчик остановится ровно на проблемной строке, а не на перехвате исключения выше по стеку.
Шаг 4. Посмотрите значения
Выделите переменную и откройте Отладка → Вычислить выражение (Shift+F9). Проверьте каждое звено цепочки по отдельности. Удобно вычислить ТипЗнч(Объект.Контрагент): если результат Неопределено или Null, источник найден.
Через окно «Стек вызовов» (Ctrl+Alt+C) поднимитесь на уровень выше и посмотрите, кто передал пустой параметр. Чинить нужно там, где значение потерялось, а не только там, где оно упало.
Шаг 5. Если ошибка только у пользователей или на сервере
Когда в отладке всё работает, откройте журнал регистрации: Администрирование → Обслуживание → Журнал регистрации. Отфильтруйте по уровню «Ошибка» и времени сбоя. В комментарии события будет тот же текст с модулем и строкой. Для клиент-серверной базы дополнительно помогает технологический журнал с событием EXCP — его настраивает администратор сервера в файле logcfg.xml.
Частые сценарии и способы исправления
Null в результате запроса
Левое соединение возвращает Null во всех полях правой таблицы, если связи нет. Код вида Выборка.Договор.Организация тогда падает.
Исправить можно двумя способами:
- в запросе — получить нужное поле прямо в тексте:
ЕСТЬNULL(Договоры.Организация, ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка)) КАК Организация; - в коде — проверить значение перед обращением:
Если ЗначениеЗаполнено(Выборка.Договор) Тогда.
Первый способ лучше: он ещё и избавляет от лишнего обращения к базе при каждом чтении реквизита через точку.
Поле составного типа
Реквизит «Субконто» или «Основание» может хранить ссылки разных типов, а иногда число или строку. Код Проводка.Субконто1.Владелец упадёт, если в субконто лежит, например, число.
Если ТипЗнч(Субконто) = Тип("СправочникСсылка.ДоговорыКонтрагентов") Тогда
Владелец = Субконто.Владелец;
КонецЕсли;
Найденная строка, которой нет
Строка = Товары.Найти(Номенклатура, "Номенклатура");
Если Строка <> Неопределено Тогда
Строка.Количество = Строка.Количество + 1;
КонецЕсли;
Таблица способов защиты
| Способ | Когда применять | Риск |
|---|---|---|
Если Х <> Неопределено Тогда | результат Найти(), ТекущиеДанные, необязательные параметры | не ловит Null |
ЗначениеЗаполнено(Х) | ссылки, где пустая ссылка тоже недопустима | вернёт «Ложь» и для нуля, и для пустой строки |
ТипЗнч(Х) = Тип(...) | поля составного типа | длинный код при многих типах |
ЕСТЬNULL() в запросе | левые соединения | нужно знать, что подставить вместо пустоты |
Попытка ... Исключение | внешние данные, где формат не гарантирован | скрывает реальные ошибки, если ничего не писать в журнал |
Правила работы с параметрами, чтобы ошибка не возвращалась
- ✅ Проверяйте параметры в начале процедуры. Пустой обязательный параметр — сразу понятное исключение через
ВызватьИсключение "Не передан параметр Контрагент"или выход. Ошибка будет внятной и в нужном месте. - ✅ Каждая ветка функции заканчивается
Возврат. Даже если этоВозврат Неопределено— так видно, что пустой результат предусмотрен, и вызывающий код его проверяет. - ✅ Не стройте длинных цепочек через точку.
Документ.Договор.Владелец.ОсновнойБанковскийСчет.Банк— четыре места для падения и четыре обращения к базе. Получите нужные поля одним запросом или функцией БСПОбщегоНазначения.ЗначенияРеквизитовОбъекта(). - ✅ Описывайте типы параметров в комментарии. Стандарт описания процедур с блоком
Параметры:подсказывает, что ждёт процедура, и помогает инструментам статического анализа. - ✅ На клиенте не рассчитывайте на реквизиты ссылок. Нужные данные готовьте на сервере и передавайте на клиент структурой.
Не лечите ошибку сплошным Попытка ... Исключение вокруг всей процедуры. Сбой исчезнет с экрана, а документ запишется с пустыми полями. Через месяц это всплывёт в отчётах, и искать причину будет намного сложнее.
Ошибка при обмене данными: что проверить
В обменах ошибка появляется при загрузке, когда правило конвертации или обработчик события получает пустое значение там, где ждёт объект.
Типичные причины:
- 🔗 Ссылка не сопоставилась. Объект из другой базы не нашёлся по ключевым полям, и в обработчик пришло
Неопределено. - 🗑️ В базе-источнике ссылка на удалённый объект. В выгрузке оказалась битая ссылка, и в приёмнике она превращается в пустое значение.
- 🧾 Доработанные правила обмена. После обновления одной из баз изменилась структура, а правила остались старыми.
- 📥 Внешние данные: JSON, XML, ответ веб-сервиса. Поле со значением
nullпри чтении становитсяНеопределено, и кодДанные.Покупатель.ИННпадает.
Что делать:
- Откройте протокол обмена или журнал регистрации и найдите, на каком объекте прервалась загрузка.
- Проверьте в базе-источнике этот объект: заполнены ли реквизиты, нет ли ссылок на удалённые элементы.
- Если ссылки битые — запустите в источнике тестирование и исправление с поиском ссылок на несуществующие объекты. Перед ТиИ сделайте резервную копию базы и выполняйте его в нерабочее время: нужен монопольный доступ, все пользователи должны выйти.
- Для типовых обменов обновите обе конфигурации до совместимых релизов. Для своих правил — добавьте в обработчики проверку на
Неопределено. - Для внешних данных проверяйте наличие и тип поля до обращения:
Если Данные.Свойство("Покупатель") И ТипЗнч(Данные.Покупатель) = Тип("Структура") Тогда.
Инструменты, которые находят опасные места до запуска
Сама ошибка возникает во время выполнения, поэтому Конфигуратор при синтаксической проверке её не покажет. Найти рискованный код заранее помогают:
| Инструмент | Что умеет |
|---|---|
Конфигурация → Проверка конфигурации в Конфигураторе | ловит синтаксис и неиспользуемые объекты, но не пустые значения |
| 1С:EDT | проверяет типы по описаниям параметров, предупреждает об обращении к возможно пустым значениям; режим строгой типизации включается комментарием //@strict-types в модуле |
| BSL Language Server, SonarQube с плагином для 1С | статический анализ, правила по стандартам разработки, отчёты по всей конфигурации |
| Автоматизированная проверка конфигураций (АПК) | проверка на соответствие стандартам разработки 1С |
| Сценарное тестирование (Vanessa Automation и аналоги) | прогоняет действия пользователя, в том числе с пустыми таблицами и незаполненными полями |
Самый дешёвый тест на эту ошибку — пройти по форме с пустыми данными: открыть документ без основания, нажать все кнопки на пустой табличной части, выбрать контрагента без договора. Большая часть сбоев всплывает за пять минут такой проверки.
Частые вопросы
Можно ли исправить ошибку без программиста?
Почему ошибка появилась после обновления, хотя раньше всё работало?
Чем эта ошибка отличается от «Поле объекта не обнаружено»?
Неопределено, Null или примитивное значение.Поможет ли очистка кэша или перезапуск 1С?
Помогает ли ЗначениеЗаполнено от Null?
Null и Неопределено функция возвращает «Ложь». Но она же вернёт «Ложь» для нуля и пустой строки, поэтому для числовых полей проверку лучше писать явно.