Форма внешней обработки перестала открываться 22.09.2026. Не ошибка в обработчике, не пустая таблица, а именно так: жмешь «Открыть» — и получаешь «К сожалению, возникла непредвиденная ситуация». В журнале регистрации ничего. Первая строка обработчика не оставила следа, хотя она там была и писала в файл.
На такой случай у меня уже лежало готовое правило, добытое за три дня возни: виновато имя. Где-то в модуле переменная или процедура названа так же, как что-то платформенное, и платформа молча ломается. Правило работало: искали столкновение имен — находили.
А потом я заглянул в типовую и увидел вот что.
// УТ 11.5, общий модуль НоменклатураСервер, строка 7912 Метаданные = ОбщегоНазначенияУТ.МетаданныеОбъектаПоПолномуИмени(ПараметрыУказанияСерий.ПолноеИмяОбъекта); // УТ 11.5, модуль формы ОтборЖурналаРегистрации, строка 52 Метаданные = Параметр;
Переменная Метаданные в типовой. В модуле формы, что важно. И конфигурация прекрасно работает у десятков тысяч людей.
Значит правило неверно — целиком или в какой-то части. Проверять его рассуждением бессмысленно: рассуждением оно и получено. 01.10.2026 мы собрали пять сборок обработки и прогнали каждую в живой базе.
Ниже — что выяснилось. Половину своих правил пришлось выбросить, зато то, что осталось, теперь можно проверить за минуту, а не за три дня.
Чем проверял
Бухгалтерия 3.0.206, платформа 8.5, внешняя обработка с одной формой. Все пробы — в модуле управляемой формы, в серверной процедуре, потому что именно там и ломалось.
Сложность тут одна, и она неприятная. Если спорная строка окажется ошибкой компиляции, умрет весь модуль: форма не откроется, ни один обработчик не сработает, и отчитаться будет некому. Один случай похоронит все остальные, и мы не узнаем даже, какой именно.
Поэтому первая сборка исполняла каждый случай через Выполнить:
Функция Проверить(Код) Попытка Выполнить(Код); Исключение Возврат "ОШИБКА: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()); КонецПопытки; Возврат "прошло"; КонецФункции
Выполнить компилирует строку в момент исполнения, поэтому ошибка становится ловимой, а не смертельной. Семнадцать случаев в одном прогоне, каждый со своим текстом.
Но у этого приема есть изъян, и его надо назвать сразу: имя функции разрешается при компиляции. Значит там, где дело именно в разрешении имени, Выполнить может показать совсем не то, что показал бы такой же код, набранный прямо в модуле. Поэтому следом я повторил те же случаи прямым кодом, каждый в отдельной функции. А случаи, которые ожидаемо убивают компиляцию, приходится пробовать по одному: там результат виден не текстом ошибки, а тем, что форма не открывается вовсе.
Контроль в каждой сборке два: заведомо неверный вызов (должен упасть) и безобидное имя (должно пройти). Без них непонятно, работает ли сама проба — и это та оговорка, которую в разборах обычно опускают.
Падают свойства
Первый и главный результат. Вот что отдает платформа, когда присваиваешь значение имени, которое занято ее свойством:
Восемь имен из девяти дали один и тот же текст — «Поле объекта недоступно для записи», и в скобках само имя:
Метаданные, Документы, Справочники, Константы, Обработки — это глобальные свойства. Параметры, Окно, ЭтаФорма — свойства управляемой формы. Для падения разницы между ними нет.
Девятое имя выбилось:
| Что присваиваем | Ответ платформы |
|---|---|
Объект = 1 |
Нельзя изменять поле, содержащее объект данных формы |
Механика простая и видна в справке: все это свойства, и у всех стоит «Только для чтения: Да». Документы — это ДокументыМенеджер, Метаданные — ОбъектМетаданныхКонфигурация. Присваивание в них и не должно работать.
Обратите внимание на последнюю строку. У основного реквизита формы текст другой, и это полезно: если вы видите «Нельзя изменять поле, содержащее объект данных формы», искать надо именно Объект, а не весь список.
Две заметки для практики. Во-первых, под удар попадают совершенно безобидные на вид строки. Параметры = Новый ПараметрыЗаписиJSON() в модуле формы — это уже падение. Для Каждого Окно Из НайденныеОкна Цикл — тоже. Во-вторых, ошибка эта исполнения, а не компиляции: модуль живет, форма открывается, и падает оно только когда до строки дойдет управление. То есть может пролежать в редкой ветке месяцами.
А вот имена функций отдаются свободно
Здесь и была моя ошибка. Правило говорило: имя платформенной функции переменной брать нельзя, переменная не создастся. Правило красивое и неверное.
имя функции как переменная: Строка | прошло, значение: текст имя функции как переменная: Тип | прошло, значение: 1 имя функции как переменная: Формат | прошло, значение: 1 имя функции как переменная: АктивноеОкно | прошло, значение: 1
Это прямой код в модуле формы, не Выполнить. Строка = "текст" работает. Тип = 1 работает. АктивноеОкно = 1 работает, хотя АктивноеОкно — глобальный метод платформы.
Больше того: в опубликованной на этом же портале конфигурации есть строка АктивноеОкно = АктивноеОкно(); — то есть переменной присваивают результат одноименного метода, и это живет в продакшене.
Красиво тут то, что правило было проверяемым все три дня. Одна сборка, одна строка, одна минута. Оно так и не было проверено, потому что работало: искали столкновения имен — находили падения. Только падали они по другой причине.
Одно объявление, и модуля нет
Зато есть класс, который действительно убивает все. Не переменная — объявление.
&НаСервере Функция Формат(Значение) Возврат "это моя функция, аргумент " + Значение; КонецФункции
Больше в сборке ничего спорного не было. Форма не открылась: «К сожалению, возникла непредвиденная ситуация». Ни одна строка модуля не исполнилась — компиляции просто не было.
Одного имени достаточно. Сначала я поставил три объявления сразу — Формат, АктивноеОкно, Строка — и форма не открылась. Можно было бы решить, что виновато количество или какое-то конкретное из трех. Оставил одно Формат — форма не открылась точно так же.
Сюда же относится и старая находка с именами процедур: обработчик команды, названный именем стандартной команды формы, дает «Процедура или функция с указанным именем уже определена», и обработка не открывается. Разница в тексте, а не в тяжести. Оговорюсь: этот случай в нынешнем прогоне не воспроизводился, он записан по прошлому проекту — так что берите его как наблюдение, а не как измеренный факт.
Итого матрица, и держать в голове надо именно ее, а не список имен:
| Класс имени | Переменной, в цикле, через Перем | Своей процедурой или функцией |
|---|---|---|
свойство: Метаданные, Документы, Параметры, Окно, Объект |
падает в рантайме | имя занято |
глобальная функция: Строка, Тип, Формат, АктивноеОкно |
работает | модуля нет |
Опасность определяет не имя. Опасность определяет пара «имя плюс как употреблено».
Три дня я лечил не ту болезнь
Остался главный вопрос. Если переменная Строка прекрасно создается, то что же тогда падало 22.09.2026?
Падало вот это:
Строка = ТаблицаДанных.Добавить(); Строка[0] = "значение"; // Получение элемента по индексу для значения не определено
Текст ошибки тогда был записан дословно, и вывод из него сделан ровно такой, какой он подсказывает: индексация не работает, потому что Строка — занятое имя. Переименовал переменную, заодно поправил еще пару мест, все заработало, правило пошло в копилку.
А дело, как оказалось, было в типе. ТаблицаДанных здесь — реквизит формы, и строка такой таблицы это не строка таблицы значений, а ДанныеФормыЭлементКоллекции. Другой тип с другим набором возможностей. Вот они рядом, один прогон:
| реквизит формы | настоящая ТаблицаЗначений | |
|---|---|---|
| тип строки | ДанныеФормыЭлементКоллекции |
Строка таблицы значений |
Строка[0] = "значение" |
не определено | работает |
Строка["А"] = "значение" |
работает | работает |
Строка.А = "значение" |
работает | работает |
метод Получить |
метода нет | есть |
метод Найти у самой таблицы |
метода нет | есть |
Числовой индекс не работает, индекс по имени колонки — работает. Переименование переменной не имело к делу никакого отношения: помогли те самые «заодно поправленные пару мест».
И посмотрите, как складно врет этот случай. Текст ошибки говорит про индекс. Справка платформы говорит, что у строки таблицы значений есть Получить и Установить и они «работают аналогично оператору []» — то есть индексация у строк таблиц вообще-то есть. Остается один вывод: раз индексация есть, а здесь ее нет, значит не разрешилось имя. Вывод неверный, но прийти к нему легко, а проверять нечего — все же работает после переименования.
Дальше ошибка начинает размножаться, и это самое неприятное. Правило «имя платформенной функции брать нельзя» объясняет не только этот случай, но и все следующие падения, в которых есть хоть одно платформенное имя. А они есть почти всегда: Строка, Параметры, Объект — слова, которыми по-русски естественно называть переменные, поэтому в любом модуле найдется хотя бы одно. Правило подтверждается на каждом шаге, никогда не опровергается и постепенно становится первым, что приходит в голову при любой непонятной поломке формы.
Отдельно стоит сказать, чего в этой истории не было. Не было ни одного случая, когда правило дало бы прямо неверный совет: переименование переменной никогда не ломает код, оно просто ничего не лечит. Значит и обратной связи, которая заставила бы правило пересмотреть, тоже не было. Ошибка такого рода живет ровно до того дня, когда ее не проверят нарочно.
Практический вывод из этой части короткий. Если у вас падает обращение к строке таблицы, первым делом смотрите, откуда взялась таблица. Реквизит формы, пусть и объявленный как таблица значений, — это коллекция данных формы, и у ее строк другой набор возможностей. И наоборот: таблица, пришедшая из запроса или созданная через Новый ТаблицаЗначений, ведет себя ровно как в справке, включая числовой индекс.
Как это ловить
Плохо ловится. Это надо сказать прямо, потому что обычный набор проверок тут бесполезен, и расчет на него — часть проблемы.
Синтаксический контроль Конфигуратора модули форм внешней обработки не компилирует вовсе: обработка собирается, отчет чистый, а модуль формы не проверялся никем. Статические анализаторы столкновений имен не видят по другой причине: для них Строка = "текст" и Метаданные = 1 — одинаково законные присваивания, разница между ними лежит в составе платформы, а не в синтаксисе. То есть вся эта группа проходит сборку зеленой, и первым, кто про нее узнает, оказывается пользователь.
Отсюда простая мысль, которая стоит дороже любого списка имен: ошибку этого класса нельзя найти проверкой, которая не запускает форму. Можно только либо не допустить, либо открыть форму и посмотреть.
Что помогает:
Смотреть на класс имени, а не на само имя. Открыть справку и посмотреть, что это — свойство или функция. У свойства будет написано «Только для чтения». Присваивание в такое имя сломается наверняка, присваивание в имя функции — нет.
Различать два симптома. Если форма открылась, а падает при нажатии кнопки — ищите присваивание свойству. Если форма не открылась совсем и даже первая строка обработчика не оставила следа — ищите свое объявление с платформенным именем. Это разные болезни, и по симптому они различаются сразу.
Оборачивать подозрительный серверный вызов в Попытку. Платформа показывает пользователю только «непредвиденную ситуацию», а ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()) сразу отдает имя и номер строки. На ошибке компиляции это, правда, не поможет: исполняться будет нечему.
Проверять утверждение прогоном, а не поиском похожего случая. Это главное. Правило работало три дня, подтверждалось на каждом следующем падении и было неверным. Подтверждалось оно потому, что я искал имена и находил, а падало по другой причине — и обе причины жили в одном коде.
Что выбросили
Своя проверялка исходников ругалась на переменные с именами функций — теперь не ругается, это не ошибка. Зато она отделила класс, которого раньше не отделяла вовсе: свое объявление с платформенным именем, то самое, от которого модуля не остается. Если у вас в правилах лежит что-то вроде «переменную Строка называть нельзя» — проверьте. Одна сборка, одна минута.
А какие имена ломали модуль у вас, и как вы на них выходили — по тексту ошибки или перебором?
Вступайте в нашу телеграмм-группу Инфостарт