Почему 1С ругается на точку после пустого значения и как это исправить

· 10 мин

Содержание

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

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

Откуда берётся ошибка: объектные и примитивные типы

В языке 1С есть значения, у которых можно спросить свойство через точку, и значения, у которых нельзя.

ЗначениеОбращение через точкуЧто будет
СправочникСсылка, ДокументСсылкаСсылка.Наименованиеработает
Структура, ТаблицаЗначений, строка таблицыСтрока.Суммаработает, если свойство есть
НеопределеноЗначение.Наименованиенаша ошибка
NULLВыборка.Контрагент.ИНН при пустом поленаша ошибка
Число, Строка, Дата, БулевоСумма.Значениенаша ошибка

Значения из трёх последних строк называют примитивными. У них нет реквизитов, табличных частей и методов, вызываемых через точку. Как только код встречает конструкцию Х.Свойство, а в Х лежит примитив, выполнение останавливается.

Отличайте её от похожих сообщений. Текст подсказывает, где искать.

Текст ошибкиЧто не так
Значение не является значением объектного типа (ИНН)слева от точки пусто или примитив
Поле объекта не обнаружено (ИНН)объект есть, но такого свойства у него нет
Метод объекта не обнаружен (Записать)объект есть, метода у него нет
Индекс находится за границами диапазонаобращение к несуществующему элементу коллекции

💡 Пустая ссылка — не примитив. Справочники.Контрагенты.ПустаяСсылка().Наименование ошибку не вызывает и возвращает пустую строку. Поэтому чаще всего виновник — именно Неопределено или NULL, а не незаполненный реквизит ссылочного типа.

Где в коде и запросах чаще всего ломается точка

Сценарии из типовых и доработанных конфигураций. Почти каждый сводится к тому, что функция или поле вернули пустоту, а код на это не рассчитывал.

  • 🔍 Поиск, который ничего не нашёл. ТаблицаЗначений.Найти() возвращает Неопределено, если строки нет. Следующая строка НайденнаяСтрока.Количество падает.
  • 📦 Соответствие без ключа. Соответствие[Ключ] при отсутствии ключа даёт Неопределено.
  • 🔗 Левое соединение в запросе. Поле из присоединённой таблицы равно NULL, если пары не нашлось. Сам запрос отрабатывает, а падает код, который обходит выборку.
  • 🧩 Составной тип реквизита. Реквизит может хранить ссылку, число или строку. Пока там ссылка — всё работает, первая же строка в нём ломает обработку.
  • ↩️ Функция без Возврат на всех ветках. Если функция выходит без возврата значения, вызывающий код получает Неопределено.
  • 🖥️ Клиентский код управляемой формы. На клиенте ссылка не «раскрывается» в реквизиты базы. Конструкции вида Объект.Контрагент.ИНН в процедуре с &НаКлиенте к данным не доберутся — их получают серверным вызовом.

Типичный пример с поиском:

НайденнаяСтрока = ТаблицаТоваров.Найти(Номенклатура, "Номенклатура");
Количество = НайденнаяСтрока.Количество; // ошибка, если строки нет

Исправленный вариант:

НайденнаяСтрока = ТаблицаТоваров.Найти(Номенклатура, "Номенклатура");
Если НайденнаяСтрока = Неопределено Тогда
    Количество = 0;
Иначе
    Количество = НайденнаяСтрока.Количество;
КонецЕсли;

В самом языке запросов разыменование NULL ошибку не даёт: Контрагенты.Ссылка.ИНН от пустого поля вернёт NULL. Проблема переезжает в код, который читает результат.

Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
    ИНН = Выборка.Контрагент.ИНН; // ошибка, если Контрагент = NULL
КонецЦикла;

Надёжнее сразу получить нужный реквизит в запросе и подстраховать пустоту функцией ЕСТЬNULL:

ВЫБРАТЬ
    Заказы.Ссылка КАК Заказ,
    ЕСТЬNULL(Договоры.Владелец.ИНН, "") КАК ИНН
ИЗ
    Документ.ЗаказКлиента КАК Заказы
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ДоговорыКонтрагентов КАК Договоры
        ПО Заказы.Договор = Договоры.Ссылка

Имена таблиц здесь условные — подставьте свои. Важен приём: реквизит забирается в запросе одним полем, а не дочитывается через точку в цикле. Это ещё и быстрее: каждое обращение Ссылка.Реквизит в цикле — отдельное чтение из базы.

Как найти строку с ошибкой и исправить модуль

Порядок действий для разработчика, у которого есть доступ к Конфигуратору или EDT.

1. Получите подробный текст

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

2. Поймайте ошибку отладчиком

  1. Откройте Конфигуратор и запустите отладку (F5).
  2. Включите Отладка → Остановка по ошибке.
  3. Повторите действие пользователя в запущенном сеансе.
  4. Отладчик остановится на проблемной строке. Откройте «Табло» или выделите выражение слева от точки и посмотрите его тип.

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

3. Выберите способ исправления

СпособКогда подходитРиск
Проверка = Неопределено или ЗначениеЗаполнено()результат поиска или функции может быть пустым по смыслунизкий
Проверка ТипЗнч(Х) = Тип("СправочникСсылка.Контрагенты")реквизит составного типанизкий
ЕСТЬNULL и выборка реквизита прямо в запроседанные приходят из запроса с соединенияминизкий
Исправить источник: заполнить реквизит, вернуть значение из функциипустоты там быть не должно по логикесредний, нужно понять бизнес-логику
Попытка ... Исключениепочти никогдавысокий: ошибка прячется, данные считаются неверно

Пример для составного типа:

Если ТипЗнч(Документ.Контрагент) = Тип("СправочникСсылка.Контрагенты") Тогда
    ИНН = Документ.Контрагент.ИНН;
Иначе
    ИНН = "";
КонецЕсли;

Для клиентского кода формы — перенос чтения на сервер:

&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    ИНН = ИННКонтрагента(Объект.Контрагент);
КонецПроцедуры

&НаСервереБезКонтекста
Функция ИННКонтрагента(Контрагент)
    Если Не ЗначениеЗаполнено(Контрагент) Тогда
        Возврат "";
    КонецЕсли;
    Возврат Контрагент.ИНН;
КонецФункции

В конфигурациях на БСП для того же есть ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Ссылка, "ИНН") — вызывайте его в серверной процедуре.

Не правьте модули типовой конфигурации на рабочей базе без копии. Сначала выгрузите информационную базу в .dt или сделайте копию средствами СУБД, а изменения переносите расширением — так они переживут следующее обновление.

Ошибка в отчётах и схеме компоновки данных

В отчёте на СКД ошибка обычно появляется при формировании или при расшифровке. Сам запрос набора данных, как уже сказано, к NULL терпим. Ломается встроенный язык вокруг схемы.

Где искать:

  • 📄 Модуль объекта отчёта. Обработчик ПриКомпоновкеРезультата и процедуры, которые донастраивают параметры: например, берут Параметр.Значение.Организация, когда параметр не заполнен.
  • 🧮 Функции общих модулей в выражениях. Вычисляемое поле или ресурс вызывает экспортную функцию, а та обращается к реквизиту переданного значения. Для итоговой строки или пустой группировки туда приходит NULL.
  • 🔎 Обработка расшифровки. Код получает значение поля из расшифровки и берёт его реквизит, а пользователь щёлкнул по ячейке итога, где поле пустое.
  • 🖨️ Печатные формы на макетах. Поле макета заполняется выражением вида Шапка.Договор.Номер, а в документе договор не указан.

Что делать:

  1. Сформируйте отчёт с минимальными отборами и повторите ошибку — так проще понять, на какой строке данных она возникает.
  2. В подробном тексте посмотрите модуль: если это МодульОбъекта отчёта или общий модуль, ищите функцию из выражения.
  3. В функции общего модуля добавьте проверку входного параметра первой строкой: Если Не ЗначениеЗаполнено(Значение) Тогда Возврат ....
  4. Если реквизит нужен только для вывода, перенесите его в запрос набора данных отдельным полем. Тогда вычисляемое поле с функцией станет не нужно.

💡 В выражениях вычисляемых полей СКД тоже работает ЕстьNULL(). Обернуть в неё аргумент функции — быстрый способ проверить догадку, прежде чем переписывать отчёт.

Почему ошибка появилась после обновления или установки расширения

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

Что изменилосьКак проявляетсяЧто проверить
Расширение написано под старый релизошибка в модуле расширенияподробный текст: имя модуля и расширения в стеке
Реквизит сменил тип на составной или переехал в табличную частьстарый код берёт реквизит через точку и получает не тоструктуру объекта в новом релизе
Внешняя печатная форма или обработкаошибка только при печати или заполненииотключить обработку и повторить действие

Для пользователя без доступа к Конфигуратору:

  1. Запишите полный текст ошибки вместе со строкой {...} из подробностей.
  2. Найдите список расширений. В типовых конфигурациях на БСП он открывается из раздела Администрирование → Печатные формы, отчеты и обработки.
  3. Посмотрите, нет ли в стеке ошибки имени расширения. Если есть — временно снимите у него флажок «Активно» и перезапустите сеанс 1С.
  4. Если ошибка ушла — обратитесь к автору расширения за версией под новый релиз.

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

Для разработчика расширения. Методы с аннотацией &Вместо переписывают типовую процедуру целиком. После обновления типовая процедура могла начать заполнять переменную по-другому, а ваша копия живёт по старым правилам. Сравните тело метода расширения с актуальным кодом типовой конфигурации. Там, где хватает, замените &Вместо на &Перед, &После или &ИзменениеИКонтроль — последний вариант сам подсветит расхождение при изменении исходного метода.

Расширения конфигурации появились в платформе 8.3.6, аннотация &ИзменениеИКонтроль — в более поздних версиях. Если база работает на старой платформе, проверьте номер в справке О программе.

Если исправить не получилось

Бывает, что код правильный, а ошибка всё равно возникает на конкретных документах.

  • 🧾 Данные с «битыми» значениями. После неудачного обмена или ручной загрузки в реквизит составного типа могло попасть значение другого типа. Найдите такие объекты запросом с отбором ТИПЗНАЧЕНИЯ(Поле) и исправьте их.
  • 🔄 Кэш конфигурации на клиенте. После обновления у отдельных пользователей встречаются странные ошибки старого кода. Запустите 1С с параметром /ClearCache — это сбрасывает локальный кэш клиента и не трогает данные.
  • 🗂️ Разные версии у пользователей. В клиент-серверном варианте проверьте, что обновление конфигурации базы данных применено, а не только загружено в основную конфигурацию.

Если ни одна гипотеза не подтвердилась, отправьте разработчику три вещи: полный текст ошибки со стеком, ссылку или номер документа, на котором она повторяется, и последовательность действий.

Как не допускать таких ошибок при разработке

Ошибка ловится заранее, если код не доверяет пустым значениям.

Перед тем как поставить точку
Выполнено: 0 / 5

Ещё несколько правил из практики:

  1. Получайте реквизиты ссылок запросом, а не цепочкой точек в цикле. Меньше обращений к базе и меньше мест для NULL.
  2. Функция, которая ищет, должна явно возвращать понятное пустое значение: пустую ссылку, ноль или Неопределено с проверкой у вызывающего.
  3. Для составных типов держите одну проверку ТипЗнч в начале обработки, а не разбросанные по коду обращения.
  4. Включайте Отладка → Остановка по ошибке при тестировании, а не только при поиске бага: так видно ошибки, которые съедает Попытка.
  5. Проверяйте доработки на пустых документах. Создайте документ, заполните только обязательные поля и проведите — сразу всплывут обращения к незаполненным реквизитам.
  6. В расширениях предпочитайте &Перед и &После вместо &Вместо: меньше кода, который устареет с новым релизом.

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

Почему ошибка возникает у одного пользователя, а у другого нет?
Обычно дело в данных или правах. У пользователей разные настройки по умолчанию, разные документы или ограничения доступа, из-за которых запрос возвращает пустое поле. Повторите действие на том же документе под учётной записью того, у кого ошибка.
Помогает ли тестирование и исправление информационной базы?
Только если причина в повреждённых данных. Если ошибка в коде, тестирование её не уберёт. Перед запуском сделайте резервную копию: режим требует монопольного доступа и завершения сеансов.
Чем ЗначениеЗаполнено отличается от проверки на Неопределено?
ЗначениеЗаполнено() возвращает Ложь и для Неопределено, и для NULL, и для пустой ссылки, ноля, пустой строки. Проверка = Неопределено ловит только одно значение. Для защиты от нашей ошибки удобнее первая.
Можно ли просто обернуть код в Попытку?
Технически да, но ошибка не исчезнет, а станет невидимой. Документ проведётся с пустой суммой или без реквизита, и это всплывёт уже в отчётности. Попытка оправдана для внешних вызовов: файлы, обмены, COM.
Ошибка во внешней обработке — что делать бухгалтеру?
Отключите обработку в справочнике дополнительных отчётов и обработок и проверьте действие типовыми средствами. Текст ошибки передайте автору обработки: исправлять придётся в её файле.