Ошибка «Значение не является значением объектного типа» в 1С возникает, когда код ставит точку после значения без свойств и методов: Неопределено, NULL, строки, числа, даты или Булево. В скобках платформа пишет имя после этой точки: Значение не является значением объектного типа (ИНН). Пустое значение появилось раньше — поиск ничего не нашёл, запрос вернул NULL, пользователь закрыл окно выбора. Ниже — сценарии с кодом «было → стало», поиск места ошибки и что делать после обновления.
Объектный тип — всё, у чего есть свойства или методы: ссылки, объекты, структуры, массивы, строки таблиц, данные формы. Примитивы — Неопределено, NULL, Строка, Число, Дата, Булево — точку не допускают. Что получится в выражении Значение.Реквизит:
| Слева от точки | Результат |
|---|---|
| Ссылка (в серверном коде), объект, структура, строка таблицы | Значение свойства; нет свойства — другая ошибка, «Поле объекта не обнаружено» |
| Пустая ссылка в коде на сервере | Пустое значение реквизита, без ошибки |
Неопределено, NULL | «Значение не является значением объектного типа (Реквизит)» |
| Строка, число, дата, Булево | Та же ошибка |
Имя в скобках — не виновник, а первое, до чего код не дотянулся. В строке Документ.Основание.Контрагент.ИНН ошибка «(ИНН)» значит, что не объект — Документ.Основание.Контрагент, а «(Контрагент)» — что уже Документ.Основание. Пустая ссылка в серверном коде цепочку не рвёт, рвут Неопределено и NULL.
Самый частый вариант ошибки «значение не является значением объектного типа» — Неопределено слева от точки: его вернул метод поиска, который ничего не нашёл. Что возвращают методы при неудаче:
| Метод | Не нашёл — вернёт |
|---|---|
ТаблицаЗначений.Найти(), Строки.Найти() у дерева значений | Неопределено |
Соответствие.Получить() и Соответствие[Ключ] | Неопределено |
СписокЗначений.НайтиПоЗначению(), НайтиПоИдентификатору() у данных формы | Неопределено |
Метаданные.Справочники.Найти(), Колонки.Найти() | Неопределено |
Ссылка.ПолучитьОбъект(), если объекта в базе нет | Неопределено |
ОбщегоНазначения.ЗначениеРеквизитаОбъекта() в БСП — для пустой и битой ссылки | Неопределено |
Своя функция, ветка которой не дошла до Возврат | Неопределено |
НайтиПоКоду(), НайтиПоНаименованию(), НайтиПоНомеру() | Пустая ссылка; Неопределено — если у справочника нет кода или наименования, у документа — номера |
Пример — загрузка прайса поставщика, где часть артикулов в базе не заведена:
// Сервер: модуль обработки загрузки прайса или общий модуль.
// Прайс — таблица значений из файла поставщика: колонки Артикул (Строка) и Цена (Число).
Функция СтрокиПрайса(Прайс) Экспорт
Результат = Новый ТаблицаЗначений;
Результат.Колонки.Добавить("Номенклатура");
Результат.Колонки.Добавить("ЕдиницаИзмерения");
Результат.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число"));
Результат.Колонки.Добавить("Комментарий", Новый ОписаниеТипов("Строка"));
НайденныеТовары = ТоварыПоАртикулам(Прайс.ВыгрузитьКолонку("Артикул"));
Для Каждого СтрокаПрайса Из Прайс Цикл
НоваяСтрока = Результат.Добавить();
НоваяСтрока.Цена = СтрокаПрайса.Цена;
// Было: НоваяСтрока.Номенклатура = НайденныеТовары[СтрокаПрайса.Артикул].Ссылка;
// Артикула нет в базе, соответствие вернуло Неопределено:
// «Значение не является значением объектного типа (Ссылка)»
Товар = НайденныеТовары.Получить(СтрокаПрайса.Артикул);
Если Товар = Неопределено Тогда
НоваяСтрока.Комментарий = СтрШаблон("Артикул %1 не найден в базе", СтрокаПрайса.Артикул);
Продолжить;
КонецЕсли;
НоваяСтрока.Номенклатура = Товар.Ссылка;
НоваяСтрока.ЕдиницаИзмерения = Товар.ЕдиницаИзмерения;
КонецЦикла;
Возврат Результат;
КонецФункции
// Соответствие «Артикул -> Структура(Ссылка, ЕдиницаИзмерения)»: один запрос на весь прайс
Функция ТоварыПоАртикулам(Артикулы)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК Ссылка,
| Номенклатура.Артикул КАК Артикул,
| Номенклатура.ЕдиницаИзмерения КАК ЕдиницаИзмерения
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул В (&Артикулы)
| И НЕ Номенклатура.ЭтоГруппа
| И НЕ Номенклатура.ПометкаУдаления";
Запрос.УстановитьПараметр("Артикулы", Артикулы);
ТоварыИзБазы = Новый Соответствие;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ТоварыИзБазы.Вставить(Выборка.Артикул,
Новый Структура("Ссылка, ЕдиницаИзмерения", Выборка.Ссылка, Выборка.ЕдиницаИзмерения));
КонецЦикла;
Возврат ТоварыИзБазы;
КонецФункции
Получить() работает как квадратные скобки, но по коду видно, что результат может быть пустым; проверка стоит сразу за ним.Товар.ЕдиницаИзмерения не читает базу на каждой строке.Неопределено: точка от пустой ссылки на сервере ошибки не даёт.Остальные приёмы работы с ключами — в статье Соответствие 1С.
НайтиПоКоду() при неудаче возвращает пустую ссылку, и чтение Ссылка.Наименование на сервере ошибки не даст. Ломается следующий шаг: ПолучитьОбъект() возвращает Неопределено, если объекта в базе нет. Второй источник — ссылка по GUID из файла обмена: ПолучитьСсылку() базу не проверяет, ссылка не пустая, а объекта за ней может не быть. Надёжные способы поиска — в статье Получить ссылку 1С.
// Сервер: обновление артикулов из файла обмена.
// Строки — таблица значений с колонками Код, Гуид (строка, может быть пустой), Артикул.
Процедура ОбновитьАртикулы(Строки) Экспорт
Для Каждого СтрокаФайла Из Строки Цикл
ТекстОшибки = "";
ТоварОбъект = ТоварДляИзменения(СтрокаФайла.Код, СтрокаФайла.Гуид, ТекстОшибки);
Если ТоварОбъект = Неопределено Тогда
Сообщить(ТекстОшибки);
Продолжить;
КонецЕсли;
ТоварОбъект.Артикул = СтрокаФайла.Артикул;
ТоварОбъект.Записать();
КонецЦикла;
КонецПроцедуры
// Было:
// ТоварОбъект = Справочники.Номенклатура.НайтиПоКоду(Код).ПолучитьОбъект();
// ТоварОбъект.Артикул = Артикул;
// Кода нет в базе: НайтиПоКоду() вернул пустую ссылку, ПолучитьОбъект() — Неопределено,
// и вторая строка падает: «Значение не является значением объектного типа (Артикул)»
Функция ТоварДляИзменения(Код, Гуид, ТекстОшибки)
Если ЗначениеЗаполнено(Гуид) Тогда
// ПолучитьСсылку() собирает ссылку из GUID, не заглядывая в базу.
// Строка не в формате GUID вызовет исключение — формат проверяйте при чтении файла
СсылкаТовара = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(Гуид));
Иначе
СсылкаТовара = Справочники.Номенклатура.НайтиПоКоду(Код);
КонецЕсли;
Если СсылкаТовара.Пустая() Тогда
ТекстОшибки = СтрШаблон("Товар с кодом %1 не найден", Код);
Возврат Неопределено;
КонецЕсли;
ТоварОбъект = СсылкаТовара.ПолучитьОбъект();
Если ТоварОбъект = Неопределено Тогда
// Ссылка не пустая, но объекта в базе нет: удалён или GUID из другой базы
ТекстОшибки = СтрШаблон("Товар %1 (%2) отсутствует в базе", Код, Гуид);
КонецЕсли;
Возврат ТоварОбъект;
КонецФункции
Ссылка.Пустая() отсекает «не нашли по коду», проверка результата ПолучитьОбъект() — удалённый объект и GUID из чужой базы. Причина отказа уходит в параметр ТекстОшибки.
Реквизит составного типа, пока в нём не выбран тип, хранит Неопределено. Если в составе типов есть Строка или Число, в нём может лежать и примитив. ЗначениеЗаполнено() здесь не спасает: непустая строка «заполнена», но точку не выдержит. Проверяйте тип:
// Сервер. Основание — реквизит составного типа: несколько видов документов и Строка
// (в старых документах основание вводили текстом).
// Было: Возврат СтрШаблон("№ %1 от %2", Основание.Номер, Формат(Основание.Дата, "ДЛФ=D"));
// Тип не выбран (Неопределено) или основание записано строкой:
// «Значение не является значением объектного типа (Номер)»
Функция ОснованиеДляПечати(Основание) Экспорт
Если Документы.ТипВсеСсылки().СодержитТип(ТипЗнч(Основание)) Тогда
Если Основание.Пустая() Тогда
Возврат ""; // вид документа выбран, сам документ — нет
КонецЕсли;
Возврат СтрШаблон("№ %1 от %2", Основание.Номер, Формат(Основание.Дата, "ДЛФ=D"));
КонецЕсли;
Если ТипЗнч(Основание) = Тип("Строка") Тогда
Возврат СокрЛП(Основание);
КонецЕсли;
Возврат ""; // Неопределено: тип не выбран
КонецФункции
Документы.ТипВсеСсылки() содержит типы ссылок всех документов, поэтому одна проверка покрывает любой вид документа в составе реквизита. Другие варианты проверки — в статье Тип значения 1С.
В запросе точка от пустой ссылки работает иначе, чем в коде: неявное соединение не находит строку, и поле получает NULL — как у левого соединения без пары. Правило: нужные реквизиты выбирайте в самом запросе через ЕСТЬNULL(), а поле выборки через точку не разыменовывайте.
// Сервер. Путь «Группа / Подгруппа / Товар» для выгрузки на сайт.
// Было: в запросе Номенклатура.Родитель.Родитель КАК ВышестоящаяГруппа,
// в цикле — Выборка.ВышестоящаяГруппа.Наименование. У товара в корне справочника
// Родитель пустой, точка от него в запросе даёт NULL:
// «Значение не является значением объектного типа (Наименование)»
Функция ПутиТоваров(СписокТоваров) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Наименование КАК Наименование,
| ЕСТЬNULL(Номенклатура.Родитель.Наименование, """") КАК ГруппаТовара,
| ЕСТЬNULL(Номенклатура.Родитель.Родитель.Наименование, """") КАК ВышестоящаяГруппа
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В (&Товары)";
Запрос.УстановитьПараметр("Товары", СписокТоваров);
Пути = Новый Массив;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Части = Новый Массив;
Если ЗначениеЗаполнено(Выборка.ВышестоящаяГруппа) Тогда
Части.Добавить(Выборка.ВышестоящаяГруппа);
КонецЕсли;
Если ЗначениеЗаполнено(Выборка.ГруппаТовара) Тогда
Части.Добавить(Выборка.ГруппаТовара);
КонецЕсли;
Части.Добавить(Выборка.Наименование);
Пути.Добавить(СтрСоединить(Части, " / "));
КонецЦикла;
Возврат Пути;
КонецФункции
// Было:
// Выборка = Запрос.Выполнить().Выбрать();
// Выборка.Следующий();
// Возврат Выборка.Товар.Наименование;
// Артикула нет: Следующий() вернул Ложь, выборка не встала на запись,
// и в Выборка.Товар нет ссылки: «...объектного типа (Наименование)»
Функция НаименованиеПоАртикулу(Артикул) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Номенклатура.Наименование КАК Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Артикул = &Артикул
| И НЕ Номенклатура.ЭтоГруппа";
Запрос.УстановитьПараметр("Артикул", Артикул);
Выборка = Запрос.Выполнить().Выбрать();
Если Не Выборка.Следующий() Тогда
Возврат "";
КонецЕсли;
Возврат Выборка.Наименование;
КонецФункции
ЕСТЬNULL(Номенклатура.Родитель.Родитель.Наименование, "") закрывает оба случая: товар в корне справочника и товар в группе первого уровня.Если Не Выборка.Следующий() Тогда — без этой проверки пустой результат запроса превращается в чтение полей выборки, которая не встала ни на одну запись.Как NULL, Неопределено и пустая ссылка ведут себя в условиях запроса, разобрано в статье Тип в запросе 1С. Где в результате появляется NULL, удобно смотреть в бесплатной консоли запросов.
В клиентском коде формы у ошибки три источника:
Элементы.Товары.ТекущиеДанные равно Неопределено, когда таблица пуста или строка не выделена.Неопределено, если окно выбора закрыли или нажали Esc, — так описан ПоказатьВыборЭлемента(), так же ведёт себя форма, закрытая без результата.// Модуль формы документа с табличной частью Товары и реквизитом Склад.
&НаКлиенте
Процедура ЗаполнитьЕдиницу(Команда)
ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
// Было: Элементы.Товары.ТекущиеДанные.ЕдиницаИзмерения = ...
// Таблица пуста или строка не выделена — ТекущиеДанные = Неопределено:
// «Значение не является значением объектного типа (ЕдиницаИзмерения)»
Если ТекущиеДанные = Неопределено Тогда
ПоказатьПредупреждение(, "Выделите строку в таблице товаров");
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(ТекущиеДанные.Номенклатура) Тогда
Возврат;
КонецЕсли;
// Было: ТекущиеДанные.ЕдиницаИзмерения = ТекущиеДанные.Номенклатура.ЕдиницаИзмерения;
// На тонком и веб-клиенте реквизиты ссылки через точку недоступны
ТекущиеДанные.ЕдиницаИзмерения = ЕдиницаТовара(ТекущиеДанные.Номенклатура);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЕдиницаТовара(Номенклатура)
Возврат Номенклатура.ЕдиницаИзмерения;
КонецФункции
&НаКлиенте
Процедура ВыбратьСклад(Команда)
СписокСкладов = СкладыДляВыбора();
СписокСкладов.ПоказатьВыборЭлемента(Новый ОписаниеОповещения("ВыборСкладаЗавершение", ЭтотОбъект), "Склад отгрузки");
КонецПроцедуры
&НаКлиенте
Процедура ВыборСкладаЗавершение(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
// Было: Объект.Склад = ВыбранныйЭлемент.Значение;
// Окно закрыли или нажали Esc — ВыбранныйЭлемент = Неопределено:
// «Значение не является значением объектного типа (Значение)»
Если ВыбранныйЭлемент = Неопределено Тогда
Возврат;
КонецЕсли;
Объект.Склад = ВыбранныйЭлемент.Значение;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СкладыДляВыбора()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Склады.Ссылка КАК Ссылка,
| Склады.Наименование КАК Наименование
|ИЗ
| Справочник.Склады КАК Склады
|ГДЕ
| НЕ Склады.ЭтоГруппа
| И НЕ Склады.ПометкаУдаления
|УПОРЯДОЧИТЬ ПО
| Наименование";
СписокСкладов = Новый СписокЗначений;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
СписокСкладов.Добавить(Выборка.Ссылка, Выборка.Наименование);
КонецЦикла;
Возврат СписокСкладов;
КонецФункции
Функция &НаСервереБезКонтекста не передаёт данные формы на сервер. В конфигурациях на БСП внутри неё можно взять ОбщегоНазначения.ЗначениеРеквизитаОбъекта(), но для пустой ссылки она вернёт Неопределено, а не пустую единицу, — так сказано в её описании в БСП 3.1.
Полный текст выглядит так: {ОбщийМодуль.ЗагрузкаПрайса.Модуль(57)}: Значение не является значением объектного типа (ЕдиницаИзмерения). В фигурных скобках — модуль и номер строки, в круглых — имя после точки, на которой код остановился.
.ЕдиницаИзмерения: выражение левее точки и есть пустое значение. Если имя встречается дважды, разнесите выражение на две строки.Попытка; Shift+F9 покажет тип левой части, «Стек вызовов» — откуда пришло пустое значение. Подробнее — в статье Отладка 1С 8.3.// Общий модуль (сервер): чтение по цепочке имён без ошибки «объектного типа».
// Путь — имена через точку: "order.courier.phone" или "Договор.Контрагент.ИНН".
// Если звено пустое (Неопределено, NULL, строка, число...), функция возвращает
// Неопределено, а в ГдеОборвалось пишет, на каком звене и что там лежало.
Функция ЗначениеПоПути(Знач Значение, Путь, ГдеОборвалось = "") Экспорт
Пройдено = Новый Массив;
Для Каждого Имя Из СтрРазделить(Путь, ".", Ложь) Цикл
ИмяСвойства = СокрЛП(Имя);
ПройденныйПуть = ?(Пройдено.Количество() = 0, "<значение>", СтрСоединить(Пройдено, "."));
Если ЭтоПримитивноеЗначение(Значение) Тогда
ГдеОборвалось = СтрШаблон("%1 = %2, а дальше нужно .%3", ПройденныйПуть, ТипЗнч(Значение), ИмяСвойства);
Возврат Неопределено;
КонецЕсли;
ТипЗначения = ТипЗнч(Значение);
Если ТипЗначения = Тип("Структура") Или ТипЗначения = Тип("ФиксированнаяСтруктура") Тогда
Если Не Значение.Свойство(ИмяСвойства) Тогда
ГдеОборвалось = СтрШаблон("в %1 нет ключа %2", ПройденныйПуть, ИмяСвойства);
Возврат Неопределено;
КонецЕсли;
Значение = Значение[ИмяСвойства];
ИначеЕсли ТипЗначения = Тип("Соответствие") Или ТипЗначения = Тип("ФиксированноеСоответствие") Тогда
Значение = Значение.Получить(ИмяСвойства);
Иначе
Значение = Значение[ИмяСвойства]; // реквизит ссылки или объекта, колонка строки таблицы
КонецЕсли;
Пройдено.Добавить(ИмяСвойства);
КонецЦикла;
Возврат Значение;
КонецФункции
// Истина для значений без свойств: точка после них даёт ошибку «объектного типа»
Функция ЭтоПримитивноеЗначение(Значение) Экспорт
Если Значение = Неопределено Или Значение = Null Тогда
Возврат Истина;
КонецЕсли;
ТипЗначения = ТипЗнч(Значение);
Возврат ТипЗначения = Тип("Строка") Или ТипЗначения = Тип("Число")
Или ТипЗначения = Тип("Дата") Или ТипЗначения = Тип("Булево");
КонецФункции
// Пример: ответ службы доставки {"order": {"id": 15, "courier": null}}
Функция ТелефонКурьера(ТекстОтвета) Экспорт
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТекстОтвета);
Ответ = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
// Было: Возврат Ответ.order.courier.phone;
// null из JSON читается как Неопределено:
// «Значение не является значением объектного типа (phone)»
ГдеОборвалось = "";
Телефон = ЗначениеПоПути(Ответ, "order.courier.phone", ГдеОборвалось);
Если Телефон = Неопределено Тогда
ЗаписьЖурналаРегистрации("Доставка.ТелефонКурьера", УровеньЖурналаРегистрации.Предупреждение, , ,
"Нет телефона курьера: " + ГдеОборвалось);
Возврат "";
КонецЕсли;
Возврат Телефон;
КонецФункции
ЭтоПримитивноеЗначение() перечисляет типы, после которых точка невозможна; ссылки, объекты и данные формы проходят дальше.Свойство(), иначе получится соседняя ошибка «Поле объекта не обнаружено». Соответствие на отсутствующий ключ вернёт Неопределено.null из JSON читается как Неопределено, поэтому ответ с "courier": null ломает цепочку Ответ.order.courier.phone ровно этой ошибкой. Подробнее — в статье JSON в 1С.| Что может прийти | Проверка |
|---|---|
| Неопределено из поиска, функции, диалога | Если Значение = Неопределено Тогда |
| NULL из запроса | ЕСТЬNULL() в тексте запроса |
| Пустая ссылка, незаполненный реквизит | ЗначениеЗаполнено(), подробно — в статье Значение заполнено 1С |
| Строка или число в составном поле | ТипЗнч() или Документы.ТипВсеСсылки().СодержитТип() |
| Пустой результат запроса | Если Выборка.Следующий() Тогда |
| Нет текущей строки в таблице формы | Если ТекущиеДанные = Неопределено Тогда |
Ставьте проверку там, где значение появилось, а не перед каждой точкой ниже по коду.
После обновления типовой ошибка чаще всплывает в доработках под прошлый релиз: типовая функция стала возвращать Неопределено в новом случае, реквизит получил составной тип, ключ параметров заполняется не всегда. Порядок разбора:
ВнешняяОбработка или ВнешнийОтчет — виноват подключённый файл, его правит автор.Исправление вносите расширением, а не правкой типового модуля, — см. Расширение конфигурации 1С.
<> Неопределено для поля запроса. NULL не равен Неопределено, условие проходит, и следующая строка падает той же ошибкой. Нужен ЕСТЬNULL() в запросе..Пустая() как проверка. На Неопределено метод падает сам: «Значение не является значением объектного типа (Пустая)». Пустое значение любого типа ловит ЗначениеЗаполнено().ЗначениеЗаполнено() перед точкой у составного поля. Строка «ДС-15 от 01.10» заполнена, а Основание.Номер всё равно упадёт — нужна проверка типа.Пустой(), забыли Следующий(). После Если Не Результат.Пустой() выборка ещё не встала на запись, и Выборка.Товар.Наименование падает.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()).Что окажется слева от точки, известно только при выполнении: функция может вернуть ссылку, а может Неопределено. Синтаксически строка Товар.Ссылка верна при любом содержимом переменной.
Там слева от точки объект, но без такого свойства. Здесь слева вообще не объект. Разбор соседней ошибки — в статье Поле объекта не обнаружено.
У него другие данные или порядок действий: не выделена строка, закрыто окно выбора, пустой составной реквизит в его документах. Бывают и права: ЗначениеРеквизитаОбъекта() с параметром ВыбратьРазрешенные = Истина при ограничении на уровне записей возвращает Неопределено.
Если после обновления ошибка всплывает в нескольких обработках и расширениях или не воспроизводится у вас, быстрее отдать разбор программисту: он найдёт звено, которое стало пустым, и поправит код через расширение. Опишите задачу на странице разместить задачу и приложите полный текст ошибки с модулем и номером строки — оценка бесплатная, ответ в течение рабочего дня; направления работ — в разделе услуги по доработке 1С.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.