Почему компилятор 1С не видит имя и как это исправить в коде
Содержание
Ошибка Переменная не определена (Имя) в 1С означает одно: компилятор встретил в модуле имя, которое в этом месте ему ничего не говорит. Оно не объявлено через Перем, ему ничего не присваивали выше, это не параметр процедуры и не свойство глобального контекста, доступное здесь. В скобках платформа пишет само проблемное имя, а в фигурных скобках перед текстом — модуль, строку и колонку.
Чаще всего причин три: опечатка в имени, обращение к серверным данным из клиентского кода (или наоборот) и реквизит, который удалили или переименовали в метаданных, а код остался старым. Ниже — как отличить один случай от другого, где искать строку и как писать код, чтобы ошибка не возвращалась.
Как 1С проверяет имена и почему ошибка всплывает до запуска кода
В 1С 8.3 модуль компилируется целиком, прежде чем выполнится хоть одна строка. На этом этапе платформа сверяет каждое имя со списком известных в данном контексте. Не нашла — модуль не компилируется, и вы видите сообщение вида:
{Документ.РеализацияТоваровУслуг.МодульОбъекта(42,15)}: Переменная не определена (СуммаДокумета)
Здесь 42 — номер строки, 15 — позиция в строке. В Конфигураторе двойной щелчок по сообщению открывает модуль на этом месте.
Отсюда важное следствие: ошибка относится ко всему модулю, а не к одной процедуре. Даже если кривая строка стоит в процедуре, которую никто не вызывает, модуль не скомпилируется. Пользователь увидит ошибку при открытии формы, проведении документа или запуске внешней обработки — в тот момент, когда платформе впервые понадобился этот модуль.
Откуда компилятор берёт «известные» имена:
- 📌 параметры текущей процедуры или функции;
- 📌 локальные переменные: объявленные через
Перемв начале процедуры или созданные первым присваиванием; - 📌 переменные модуля, объявленные через
Перемв его начале; - 📌 экспортные переменные модуля управляемого приложения (только в клиентском коде);
- 📌 реквизиты и табличные части объекта — в модуле объекта и модуле менеджера записи;
- 📌 свойства и методы глобального контекста, доступные в текущем контексте исполнения;
- 📌 имена общих модулей, если модуль доступен там, откуда его вызывают.
В 1С нет режима обязательного объявления переменных. Присваивание Имя = Значение само создаёт локальную переменную. Поэтому ошибку даёт именно ЧТЕНИЕ неизвестного имени: в правой части присваивания, в условии, в параметре вызова.
Типичные ситуации, в которых возникает «Переменная не определена»
Опечатка в имени
Самый частый случай. Переменную объявили под одним именем, а читают под другим:
СуммаДокумента = 0;
Для Каждого СтрокаТЧ Из Товары Цикл
СуммаДокумента = СуммаДокумета + СтрокаТЧ.Сумма; // пропущена «н»
КонецЦикла;
Компилятор сообщит Переменная не определена (СуммаДокумета). Обратная опечатка опаснее: если ошибиться в левой части, платформа молча создаст новую переменную, и ошибки не будет вовсе — будет неверный результат.
Частая разновидность опечатки — латинская буква в русском слове: Сyмма с латинской «y» или Cчёт с латинской «C». Глазом не отличить. Выручает поиск по модулю (Ctrl+F) по правильному написанию: если строка не находится, внутри имени чужая буква.
Обращение к форме из процедуры без контекста
В модуле управляемой формы процедура с директивой &НаСервереБезКонтекста не видит ни данных формы, ни её реквизитов:
&НаСервереБезКонтекста
Процедура ЗаполнитьКомментарийНаСервере()
Объект.Комментарий = "Заполнено автоматически"; // Переменная не определена (Объект)
КонецПроцедуры
Варианта исправления два. Первый — сменить директиву на &НаСервере, тогда на сервер уйдут данные формы. Второй, более экономный по трафику, — передать нужное значение параметром и вернуть результат функцией:
&НаКлиенте
Процедура Заполнить(Команда)
Объект.Комментарий = ТекстКомментария(Объект.Контрагент);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ТекстКомментария(Контрагент)
Возврат "Контрагент: " + Строка(Контрагент);
КонецФункции
То же касается Элементы и ЭтаФорма — в процедурах без контекста их нет.
Серверные объекты в клиентском коде
На тонком клиенте нет доступа к базе данных. Поэтому в процедуре &НаКлиенте не определены Справочники, Документы, РегистрыСведений, ПараметрыСеанса и другие менеджеры прикладных объектов:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Валюта = Справочники.Валюты.НайтиПоКоду("643"); // Переменная не определена (Справочники)
КонецПроцедуры
Для предопределённых элементов и пустых ссылок на клиенте есть функция ПредопределенноеЗначение("Справочник.Валюты.ПустаяСсылка"). Всё, что требует запроса к базе, выносят в серверную функцию.
Область видимости переменных: модуль, процедура, клиент и сервер
Локальные переменные и переменные модуля
Локальная переменная живёт, пока выполняется процедура. В соседней процедуре её имени нет. Если два метода должны работать с одним значением, есть три пути:
- Передать значение параметром — самый прозрачный вариант.
- Вернуть его из функции.
- Объявить переменную модуля через
Перемв начале модуля, до первой процедуры.
Переменные модуля формы: у клиента и сервера свои
В модуле управляемой формы переменная модуля объявляется с директивой и существует только в своём контексте:
&НаКлиенте
Перем КэшЦен;
Такую переменную видят только клиентские процедуры. Серверная процедура этой формы прочитать КэшЦен не может — получите Переменная не определена (КэшЦен). Переменная модуля с директивой &НаСервере тоже не спасает: серверный контекст формы между вызовами не сохраняется, и значение каждый раз начинается заново.
Если данные нужны и клиенту, и серверу формы, создайте реквизит формы. Он передаётся между контекстами и доступен с обеих сторон.
Глобальные переменные
В общих модулях раздела переменных нет совсем — объявить там Перем нельзя. «Глобальную» переменную для клиента объявляют в модуле управляемого приложения со словом Экспорт. На сервере она недоступна.
| Где нужна переменная | Чем заменить |
|---|---|
| В нескольких процедурах одного модуля | Переменная модуля (Перем в начале модуля) |
| На клиенте и на сервере формы | Реквизит формы |
| Во всех клиентских модулях сеанса | Экспортная переменная модуля управляемого приложения |
| На сервере в течение сеанса | Параметр сеанса (объект метаданных «Параметры сеанса») |
| Повторно вычисляемое значение | Общий модуль с повторным использованием возвращаемых значений |
Реквизиты объектов и форм: почему имя реквизита «не видно»
Модуль объекта и модуль формы обращаются к реквизитам по-разному
В модуле объекта реквизиты доступны напрямую по имени: Если СуммаДокумента = 0 Тогда. В модуле управляемой формы прямого доступа нет. Реквизиты объекта лежат внутри основного реквизита формы, обычно он называется Объект:
// модуль объекта — так можно
Если Не ЗначениеЗаполнено(Контрагент) Тогда
// модуль управляемой формы — нужно через Объект
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
Код, перенесённый из модуля объекта в форму без правки, даёт ошибку на каждом реквизите. Обратный перенос — тоже: в модуле объекта имени Объект нет, там используют ЭтотОбъект.
Реквизит удалили или переименовали
Ещё одна частая причина — изменение метаданных. Разработчик переименовал реквизит, а в одном из модулей осталось старое имя. Поведение при этом разное:
- ❌ в модуле объекта старое имя без точки — это ошибка компиляции
Переменная не определена (СтароеИмя); - ❌ обращение через точку (
Объект.СтароеИмя,Документ.СтароеИмя) компилятор не проверяет — ошибкаПоле объекта не обнаружено (СтароеИмя)появится только при выполнении строки.
Переименование через свойства объекта в Конфигураторе не правит код автоматически. Перед переименованием найдите все упоминания через глобальный поиск Ctrl+Shift+F по всей конфигурации.
Похожие ошибки, которые путают с этой
| Текст ошибки | Когда возникает | Что означает |
|---|---|---|
Переменная не определена (Х) | При компиляции модуля | Имя без точки не известно в этом контексте |
Процедура или функция с указанным именем не определена (Х) | При компиляции | Вызван метод, которого нет или который недоступен из этого контекста |
Тип не определен (Х) | При выполнении Новый Х | Тип не существует или недоступен в контексте, например Новый Запрос на клиенте |
Поле объекта не обнаружено (Х) | При выполнении | Через точку запрошено свойство, которого у объекта нет |
Метод объекта не обнаружен (Х) | При выполнении | Через точку вызван несуществующий метод |
Значение не является значением объектного типа (Х) | При выполнении | Переменная есть, но в ней Неопределено или примитивное значение |
Диагностика: как найти строку с ошибкой и проверить все модули
Проверка синтаксиса одного модуля
Откройте модуль в Конфигураторе и нажмите Ctrl+F7. Платформа проверит синтаксис и выведет ошибки в окно сообщений. Двойной щелчок по строке сообщения ставит курсор на место ошибки.
Проверка учитывает директивы компиляции, поэтому обращение к Справочники в клиентской процедуре будет поймано сразу.
Проверка всей конфигурации
Если ошибка всплыла после доработки или объединения конфигураций, проверять модули по одному долго. Откройте Конфигурация → Проверка конфигурации:
- Отметьте флажок логической целостности и проверку модулей.
- Выберите режимы, в которых работают пользователи: тонкий клиент, веб-клиент, сервер, внешнее соединение.
- Нажмите «Выполнить» и пройдите по списку сообщений.
Проверка по каждому режиму отдельно важна: модуль может нормально компилироваться на сервере и падать в тонком клиенте.
Отладчик для ошибок при выполнении
Компиляционная ошибка ловится проверкой синтаксиса. Но если имя собирается строкой и выполняется через Выполнить() или Вычислить(), компилятор его заранее не видит:
ТекстКода = "Результат = Цена * Количество";
Выполнить(ТекстКода); // Переменная не определена (Количество), если её нет в процедуре
Здесь поможет отладчик. Поставьте точку останова (F9) перед вызовом, запустите отладку (F5) и посмотрите в табло, какие переменные существуют на этот момент. Строку, переданную в Выполнить(), выводите в окно сообщений перед вызовом — так видно, какое имя на самом деле пришло.
В 1С:EDT неизвестные имена подсвечиваются прямо при наборе, без отдельной проверки. Для больших доработок это экономит много проходов «изменил — проверил».
Ошибка появилась у пользователя: что делать без программиста
Бухгалтер обычно видит это сообщение не в коде, а при открытии документа, отчёта или внешней обработки. Что можно сделать самостоятельно:
- 🔍 Ошибка при открытии внешней обработки или отчёта (файл
.epf/.erf). Обработка написана под другую конфигурацию или старый релиз. Запросите у автора версию под ваш релиз. - 🔍 Ошибка сразу после обновления типовой конфигурации. Скорее всего, в базе есть доработки или расширения, которые ссылаются на старые имена. Посмотрите список расширений в
Администрирование → Печатные формы, отчеты и обработки → Расширенияи попробуйте временно отключить подозрительное расширение — только по согласованию с тем, кто отвечает за базу. - 🔍 Ошибка в типовой базе без доработок. Проверьте, что обновление прошло до конца, а не прервалось на середине. Скопируйте полный текст ошибки с именем модуля и номером строки — без этого программисту придётся искать вслепую.
Не открывайте модули в Конфигураторе рабочей базы «посмотреть и поправить». Любая правка снимает типовую конфигурацию с полной поддержки или требует включения возможности изменений. Сначала — резервная копия базы и согласование с ответственным за конфигурацию.
Как писать код, чтобы ошибка не повторялась
Несколько привычек, которые почти исключают «Переменная не определена»:
- Объявляйте переменные явно. Строка
Перем Итог;в начале процедуры или стартовое присваиваниеИтог = 0;делают намерение очевидным. - Используйте контекстную подсказку. Начните имя и нажмите
Ctrl+Пробел— Конфигуратор подставит имя без опечаток и предложит только то, что доступно в этом месте. - Ставьте директиву каждой процедуре формы. Процедура без директивы в форме считается серверной. Явная директива сразу показывает, к чему здесь есть доступ.
- По умолчанию берите
&НаСервереБезКонтекста, а данные передавайте параметрами. Ошибку проОбъектвы увидите при первой проверке синтаксиса, а не у пользователя. - Не храните общее состояние в переменных модуля формы. Для обмена между клиентом и сервером есть реквизиты формы.
- Переименовывайте через поиск. Перед сменой имени реквизита ищите упоминания по всей конфигурации, включая расширения и внешние обработки.
- Запускайте
Проверку конфигурацииперед выпуском. Особенно после объединения конфигураций и обновления на новый релиз. - Пишите одним алфавитом. Держите раскладку под контролем при наборе русских имён.