Почему 1С не может прочитать реквизит через точку: разбор ошибки объектного типа и способы её устранить
Содержание
Ошибка Значение не является значением объектного типа (Контрагент) значит одно: код обратился к свойству через точку, а слева от точки оказался не объект. Чаще всего там Неопределено или NULL, реже строка, число или дата. В скобках 1С пишет имя свойства, которое пыталась прочитать, — это главная подсказка, с неё и начинается поиск.
Исправить ошибку можно двумя путями. Если она появилась в типовой конфигурации после обновления или в одном конкретном документе, обычно хватает пользовательских действий: перезапуска, проверки данных, отключения внешней обработки. Если ошибка в своём коде или доработке, её устраняют в конфигураторе — находят строку и добавляют проверку значения перед обращением к реквизиту.
Техническая суть: почему значение не является объектом
В языке 1С через точку можно читать свойства только у значений «объектных» типов. Это ссылки (СправочникСсылка, ДокументСсылка), объекты (СправочникОбъект), структуры, строки таблиц значений, данные форм и подобные коллекции.
У примитивных значений свойств нет. Если переменная содержит одно из них, обращение Переменная.Что-то падает с этой ошибкой:
- ⚪
Неопределено— переменной ничего не присвоили, функция ничего не вернула, поиск ничего не нашёл; - ⚫
NULL— пустое поле из запроса, обычно после левого соединения; - 🔤
Строка,Число,Дата,Булево— в реквизит составного типа попало не то значение.
Пример, который воспроизводит ошибку в две строки:
Контрагент = Неопределено;
ИНН = Контрагент.ИНН; // Значение не является значением объектного типа (ИНН)
Полный текст сообщения обычно выглядит так:
{Документ.РеализацияТоваровУслуг.Форма.ФормаДокумента.Форма(412)}: Значение не является значением объектного типа (Склад)
В фигурных скобках — модуль, в круглых после модуля — номер строки. Для программиста этого достаточно, чтобы открыть модуль
и перейти к строке через Ctrl+G.
Имя в скобках — свойство справа от точки. Ошибочное значение — то, что стоит слева от него. В выражении Документ.Контрагент.ИНН с ошибкой (ИНН) пустым оказался Документ.Контрагент, а не сам документ.
Пять типичных ситуаций, где возникает ошибка
1. В табличной части не выбрана строка
Классика управляемых форм. Обработчик кнопки читает Элементы.Товары.ТекущиеДанные.Номенклатура, а пользователь не выделил ни одной строки или таблица пуста. Свойство ТекущиеДанные в этот момент равно Неопределено.
2. Поиск по коллекции ничего не нашёл
Метод Найти() у таблицы значений, списка значений и массива возвращает Неопределено, если совпадения нет. Код, написанный в расчёте на «всегда найдётся», падает на первом же непредусмотренном случае.
3. Поле запроса пришло пустым
При ЛЕВОЕ СОЕДИНЕНИЕ поля присоединённой таблицы для строк без пары равны NULL. Обращение Выборка.Договор.Номер при пустом договоре даёт ту же ошибку. Сюда же относится выборка ссылки через точку в самом запросе, если промежуточное поле пустое у части строк.
4. Функция вернула не то
Функция без Возврат в одной из веток возвращает Неопределено. Пока тестировали на «правильных» данных, всё работало. Достаточно одной записи, которая идёт по другой ветке условия, — и вызывающий код ломается.
5. Объект по битой ссылке
ПолучитьОбъект() по ссылке на удалённый элемент возвращает Неопределено. В интерфейсе такие ссылки видны как <Объект не найден> с внутренним идентификатором. Следующая строка Объект.Записать() или Объект.Наименование и даёт ошибку.
Пошаговая диагностика ошибки объектного типа
Действуйте по порядку. Первые три шага доступны пользователю без конфигуратора.
- Скопируйте полный текст. В окне ошибки нажмите ссылку подробного текста: там будет модуль и номер строки. Без них поиск превращается в гадание.
- Определите, чья это часть. Если в пути модуля стоит
ВнешняяОбработкаилиВнешнийОтчет, виновата внешняя доработка, а не конфигурация. Если в начале имя расширения — ошибка в расширении. - Проверьте повторяемость. Ошибка на одном документе и нет на соседнем — дело в данных этого документа. Ошибка везде — дело в коде или в обновлении.
- Найдите строку в конфигураторе. Откройте модуль,
Ctrl+G, номер строки. Посмотрите, какое выражение стоит слева от свойства из скобок. - Включите остановку по ошибке. В конфигураторе в меню
Отладкаесть режим остановки по ошибке. Запустите отладку (F5), повторите действие — отладчик встанет ровно на проблемной строке. - Посмотрите значение. Наведите курсор на переменную или откройте табло (
Shift+F9). УвидитеНеопределено,NULLили значение неожиданного типа. - Найдите, откуда оно пришло. Поднимитесь по стеку вызовов: где переменную заполнили, какой запрос вернул пустое поле, какая ветка функции не вернула результат.
Отладку на рабочей базе с живыми пользователями ведите аккуратно: остановка на точке прерывания держит ваш сеанс, но транзакции и блокировки, открытые кодом, тоже висят, пока вы не продолжите выполнение. Надёжнее воспроизвести ошибку на копии базы.
Исправление в коде: типовые случаи и примеры
Общий принцип: перед обращением через точку убедитесь, что значение есть и у него нужный тип. Ниже готовые варианты под каждую ситуацию.
Пустые ТекущиеДанные
&НаКлиенте
Процедура ПодобратьЦену(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Сообщить("Выделите строку табличной части.");
Возврат;
КонецЕсли;
ЗаполнитьЦенуНаСервере(ТекущиеДанные.ПолучитьИдентификатор());
КонецПроцедуры
Результат поиска в коллекции
Строка = ТаблицаЦен.Найти(Номенклатура, "Номенклатура");
Если Строка = Неопределено Тогда
Цена = 0;
Иначе
Цена = Строка.Цена;
КонецЕсли;
NULL из запроса
Самое чистое решение — убрать NULL в самом запросе через ЕСТЬNULL:
Запрос.Текст =
"ВЫБРАТЬ
| Реализация.Ссылка КАК Документ,
| ЕСТЬNULL(Договоры.Номер, """") КАК НомерДоговора
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК Договоры
| ПО Реализация.ДоговорКонтрагента = Договоры.Ссылка";
Если поле нужно именно как ссылка, проверяйте его в коде: Если Выборка.Договор <> NULL Тогда. Лучше вообще не читать реквизиты через точку от поля выборки, а сразу выбрать нужное поле в запросе — это и быстрее, и без риска.
Реквизит составного типа
Если ТипЗнч(Документ.Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
ИНН = Документ.Контрагент.ИНН;
Иначе
ИНН = "";
КонецЕсли;
Функция, которая обязана вернуть значение
Последней строкой функции ставьте Возврат со значением по умолчанию. Тогда ни одна ветка условия не «провалится» в Неопределено.
Объект по ссылке
ОбъектДокумента = Ссылка.ПолучитьОбъект();
Если ОбъектДокумента = Неопределено Тогда
ВызватьИсключение "Документ не найден в базе: возможно, он удалён.";
КонецЕсли;
ОбъектДокумента.Комментарий = "Проверено";
ОбъектДокумента.Записать();
В конфигурациях на БСП (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) для чтения одного реквизита по ссылке есть серверная функция ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН"). Она читает поле запросом и не требует получать объект целиком.
Не глушите ошибку конструкцией Попытка … Исключение без обработки. Код перестанет падать, но пустое значение тихо уйдёт дальше: в проводку, в отчёт, в обмен. Найти такую ошибку потом в разы тяжелее.
Скрытые причины: когда сообщение указывает не туда
Иногда строка с ошибкой — лишь место, где проблема проявилась. Источник лежит раньше.
- 🔗 Битые ссылки в данных. Элемент удалили напрямую, минуя контроль ссылочной целостности, или он не пришёл при обмене. Документы ссылаются в пустоту, и код, который получает объект по такой ссылке, падает. Проверка:
Тестирование и исправлениев конфигураторе с поиском ссылок на несуществующие объекты. Запускайте её только на копии или после полной выгрузки базы в.dt: режим требует монопольного доступа, все пользователи должны выйти. - 🧩 Расширение после обновления. В новом релизе разработчики переименовали реквизит или изменили его тип, а расширение читает по старой схеме. Ошибка появляется сразу у всех и сразу после обновления.
- 📄 Внешние печатные формы и обработки. Написаны под другой релиз или другую конфигурацию. Обращаются к реквизиту, которого в вашей базе нет или который заполняется иначе.
- 🔄 Обмен данными. Объект загружен частично: шапка пришла, связанный справочник — нет. Реквизит выглядит заполненным, но ссылка ведёт на несуществующий элемент.
- 🧮 Устаревший кэш. После обновления конфигурации клиент может держать старые метаданные. Запуск с ключом
/ClearCacheубирает этот вариант из списка подозреваемых. Ключ очищает только локальный кэш вашего клиента, сеансы других пользователей он не затрагивает.
Если подозреваете битые ссылки, сначала сделайте резервную копию. Автоматическое исправление в режиме тестирования может создать объекты-заглушки или очистить ссылки — результат лучше проверить на копии, а уже потом повторять на рабочей базе.
Как не допускать таких ошибок в своём коде
- ✅ Проверяйте
ТекущиеДанныенаНеопределенов каждом клиентском обработчике, который с ними работает. - ✅ Результат
Найти(),ПолучитьОбъект(), чтения из соответствия черезПолучить()сразу проверяйте наНеопределено. - ✅ В запросах оборачивайте поля из левого соединения в
ЕСТЬNULLи выбирайте нужные реквизиты сразу, а не «разыменовывайте» их потом в коде. - ✅ Для реквизитов составного типа проверяйте
ТипЗнч()перед обращением к полям. - ✅ Заканчивайте каждую функцию явным
Возвратс безопасным значением. - ✅ Не используйте цепочки длиннее двух точек вида
Документ.Договор.Организация.ИНН: каждая точка — место, где значение может оказаться пустым, и лишний запрос к базе. - ✅ Изменения типовой конфигурации держите в расширении и после каждого обновления прогоняйте основные сценарии на копии базы.
- ✅ Запускайте синтаксический контроль с расширенной проверкой и, если есть возможность, автоматические проверки кода (АПК или проверки в EDT): они находят часть потенциальных обращений к
Неопределенодо запуска.
Чем эта ошибка отличается от похожих сообщений 1С
Похожие тексты часто путают, хотя причины у них разные. Сравнение поможет быстрее понять, что именно сломалось.
| Сообщение | Что произошло | Куда смотреть |
|---|---|---|
Значение не является значением объектного типа (Х) | Слева от точки примитив: Неопределено, NULL, строка, число | Откуда пришло значение слева от Х |
Поле объекта не обнаружено (Х) | Объект есть, но свойства Х у него нет | Имя реквизита, ключ структуры, колонка таблицы |
Метод объекта не обнаружен (Х) | Объект есть, но метода Х у этого типа нет или он недоступен в этом контексте | Тип значения и директива компиляции (клиент или сервер) |
Переменная не определена (Х) | Имя Х нигде не объявлено и не присвоено | Опечатка в имени, переменная из другого модуля |
Индекс находится за границами диапазона | Обращение по номеру к несуществующему элементу коллекции | Количество элементов и расчёт индекса |
Преобразование значения к типу Число не может быть выполнено | Строку пытаются превратить в число | Формат исходной строки |
Ключевое отличие первой строки от второй: при «поле не обнаружено» объект существует, просто у него нет такого свойства. При «не является значением объектного типа» объекта нет вовсе — есть пустое или примитивное значение.