Откуда берётся сбой при обращении к элементу коллекции по номеру и как его устранить

· 10 мин

Содержание

Ошибка Индекс находится за границами массива в 1С означает, что код запросил элемент коллекции по номеру, которого в ней нет. Например, в массиве 3 элемента с индексами 0, 1 и 2, а программа обращается к Массив[3]. Платформа прерывает выполнение и показывает модуль и строку, где это случилось. Исправляют ошибку в коде: проверяют количество элементов до обращения или обходят коллекцию без индекса.

Ошибка платформенная и одинакова для любой конфигурации на 1С 8.3: Бухгалтерии, ЗУП, УТ, самописных баз. Обычно она живёт в доработках, внешних обработках, расширениях и загрузках из файлов. В типовом коде без доработок встречается редко и чаще всего указывает на нестандартные данные.

Почему 1С выдаёт ошибку «индекс за границами массива»

В 1С нумерация элементов в индексируемых коллекциях начинается с нуля. Последний элемент имеет индекс Количество() - 1. Любое обращение с индексом меньше нуля или больше последнего — выход за границы.

Как это выглядит на примере:

КоллекцияКоличество()Допустимые индексыВГраница()
Массив из 3 элементов30, 1, 22
Массив из 1 элемента100
Пустой массив0нет ни одного-1

Ошибку дают не только массивы. Тот же текст появляется при обращении по индексу к строкам таблицы значений (ТЗ[5]), к табличной части документа (Товары[0]), к результату Выгрузить() запроса и к другим коллекциям с доступом по номеру. Методы Получить(Индекс) и Удалить(Индекс) с несуществующим номером тоже приводят к этой ошибке.

Сообщение обычно выглядит так:

{Обработка.ЗагрузкаПрайса.Форма.Форма.Форма(142)}: Ошибка при вызове метода контекста (Получить)
	Строка = Строки.Получить(НомерСтроки);
по причине:
Индекс находится за границами массива

В фигурных скобках — объект и модуль, в круглых — номер строки. Это главная подсказка для поиска.

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

Типичные ситуации, в которых возникает выход за границы массива

На практике причин немного, и почти все сводятся к шести шаблонам.

  • 🔢 Цикл до Количество() вместо Количество() - 1. Классическая ошибка на единицу: Для Инд = 0 По Массив.Количество() Цикл. Последняя итерация обращается к несуществующему элементу.
  • 📭 Обращение к первому элементу пустой коллекции. Результат.Выгрузить()[0] при пустом результате запроса, ВыделенныеСтроки[0], когда пользователь ничего не выделил.
  • ✂️ Разбор строки на части. Части = СтрРазделить(Строка, ";"), затем Части[3]. Если в строке файла не четыре поля, а три, загрузка падает.
  • 🗑️ Удаление элементов в прямом цикле. После удаления коллекция сокращается, а счётчик идёт до старой границы.
  • 📄 Данные из внешнего файла. В Excel или CSV пропущена колонка, пустая последняя строка, другой разделитель — и индекс колонки уже не существует.
  • 🔁 Две параллельные коллекции. Код берёт Цены[Инд] для Товары[Инд], предполагая, что размеры совпадают. Стоит одной из них оказаться короче — сбой.

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

Диагностика: выберите симптом

Что делать пользователю, если ошибка появилась при работе в базе

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

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

Не пытайтесь «пройти» ошибку повторным нажатием или правкой документа наугад. Обработка могла успеть записать часть данных до сбоя. Сначала посмотрите, что изменилось, и только потом повторяйте.

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

Как найти место ошибки в коде: отладчик и журнал

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

Остановка по ошибке

Самый быстрый способ — заставить отладчик остановиться ровно в момент исключения.

  1. Откройте базу в Конфигураторе. Работайте на копии, если ошибку можно воспроизвести на ней.
  2. Запустите отладку: Отладка → Начать отладку и выберите нужный клиент.
  3. Включите Отладка → Остановка по ошибке. В окне можно указать текст ошибки, чтобы отладчик не останавливался на других исключениях: впишите Индекс находится за границами массива.
  4. Повторите действие пользователя. Выполнение остановится на проблемной строке.
  5. Посмотрите значения: наведите курсор на переменную или откройте Отладка → Табло и добавьте туда индекс и Коллекция.Количество().

Отладка в рабочей клиент-серверной базе мешает пользователям: при остановке на точке серверный вызов ждёт, а отладку на сервере нужно разрешать в настройках службы 1С. Ошибку лучше воспроизводить на копии базы. Если без рабочей базы не обойтись, делайте это вне рабочего времени.

Когда ошибка в фоновом или регламентном задании

Интерактивно такой сбой не воспроизвести. Текст ошибки фонового задания попадает в журнал регистрации: откройте Администрирование → Обслуживание → Журнал регистрации и отберите события с уровнем «Ошибка» за нужный период. В событии будет тот же путь к модулю и номер строки.

Для поиска причины на данных временно добавьте запись в журнал перед проблемным обращением:

ЗаписьЖурналаРегистрации("Отладка.ЗагрузкаПрайса", УровеньЖурналаРегистрации.Информация, , ,
	СтрШаблон("Строка %1: полей %2, индекс %3", НомерСтроки, Части.Количество(), ИндексПоля));

После исправления такую запись удалите, чтобы не засорять журнал.

Ошибка воспроизводится не всегда

Значит, дело в данных. Зафиксируйте, на каком объекте происходит сбой, и сравните его с объектом, где всё работает. Обычно разница видна сразу: пустая табличная часть, одна строка вместо нескольких, отсутствующий реквизит в строке файла.

Как писать циклы и проверки без выхода за границы массива

Большинство исправлений сводится к четырём приёмам.

1. Обход без индекса

Если номер элемента не нужен, используйте Для Каждого. Выйти за границы в таком цикле невозможно:

Для Каждого СтрокаТовара Из Объект.Товары Цикл
	Сумма = Сумма + СтрокаТовара.Сумма;
КонецЦикла;

2. Правильная граница индексного цикла

Когда индекс нужен, верхняя граница — Количество() - 1 или ВГраница(). Для пустого массива ВГраница() вернёт -1, и цикл Для Инд = 0 По -1 не выполнится ни разу:

Для Инд = 0 По Массив.ВГраница() Цикл
	Сообщить(СтрШаблон("%1: %2", Инд, Массив[Инд]));
КонецЦикла;

Обратите внимание: у таблицы значений и табличных частей метода ВГраница() нет, для них используйте Количество() - 1.

3. Проверка перед обращением

Перед [0] или обращением к полю по номеру проверяйте размер:

Части = СтрРазделить(СтрокаФайла, ";");
Если Части.Количество() < 4 Тогда
	Сообщить(СтрШаблон("Строка %1 пропущена: полей %2 вместо 4", НомерСтроки, Части.Количество()));
	Продолжить;
КонецЕсли;
Цена = Части[3];

Для результата запроса удобнее не выгружать таблицу, а взять выборку:

Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
	Курс = Выборка.Курс;
Иначе
	Курс = 1;
КонецЕсли;

4. Удаление в обратном порядке

При удалении идите от конца к началу. Тогда удаление текущего элемента не сдвигает элементы, которые ещё предстоит проверить:

ВсегоСтрок = Объект.Товары.Количество();
Для Сч = 1 По ВсегоСтрок Цикл
	СтрокаТовара = Объект.Товары[ВсегоСтрок - Сч];
	Если СтрокаТовара.Количество = 0 Тогда
		Объект.Товары.Удалить(СтрокаТовара);
	КонецЕсли;
КонецЦикла;

Исходный размер запоминается один раз до цикла. Индекс ВсегоСтрок - Сч идёт от последней строки к первой: при 3 строках это 2, 1, 0. Удаление строки с индексом 2 не сдвигает строки 0 и 1, поэтому каждая строка проверяется ровно один раз. Если же считать индекс от текущего Количество(), после удаления одна строка будет пропущена.

Второй вариант — сначала собрать удаляемые строки в отдельный массив обычным Для Каждого, а потом удалить их вторым циклом.

Обход, поиск или индекс: какой способ работы с коллекцией выбрать

СпособКогда подходитРиск выхода за границы
Для Каждого … ИзНужно обработать все элементы, номер не важенНет
Для Инд = 0 По ВГраница()Нужен номер или сравнение соседних элементовТолько при ошибке в границе или изменении коллекции в цикле
Прямое обращение [N]Структура гарантирована: фиксированный массив, заранее проверенный размерВысокий без проверки Количество()
Найти()Нужно найти элемент по значениюНет: при отсутствии вернётся Неопределено
Выборка запроса Следующий()Нужна одна или несколько записей из запросаНет
Обратный циклУдаление элементов по условиюНет, если граница считается от текущего размера

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

Отдельно о Попытка … Исключение. Обёртка ловит ошибку, но не исправляет её. Она уместна при загрузке внешних данных, где кривая строка — нормальная ситуация: запишите проблему и идите дальше. Прятать в неё ошибку на единицу в собственном цикле нельзя: данные обработаются не полностью, а пользователь этого не увидит.

Попытка
	ОбработатьСтроку(Части);
Исключение
	ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
	Сообщить(СтрШаблон("Строка %1 не загружена: %2", НомерСтроки, ТекстОшибки));
КонецПопытки;

Как не допустить сбой в новом коде и типичные промахи

Несколько привычек снимают проблему почти полностью.

  • ✅ Не меняйте коллекцию внутри цикла, который её обходит. Ни добавлений, ни удалений в прямом обходе.
  • ✅ Не доверяйте внешним данным. Каждую строку файла, ответ веб-сервиса и выделение пользователя проверяйте на количество элементов.
  • ✅ Не связывайте коллекции по номерам. Вместо двух параллельных массивов используйте таблицу значений или соответствие, где связь хранится явно.
  • ✅ Обращайтесь к колонкам по имени, а не по номеру. Строка.Цена переживёт добавление колонки, Строка[3] — нет.
  • ✅ Тестируйте на крайних случаях: пустая табличная часть, ровно одна строка, файл без последней колонки.

Промахи, которые встречаются при исправлении:

  • ❌ Заменить По Количество() на По Количество() - 2 «на всякий случай». Последний элемент перестаёт обрабатываться, и ошибка превращается в тихую потерю данных.
  • ❌ Добавить проверку на Количество() > 0, когда код обращается к [1]. Для одного элемента сбой останется: проверять нужно Количество() > 1.
  • ❌ Исправить ошибку прямо в типовом модуле без расширения. При следующем обновлении правка либо потеряется, либо усложнит обновление. Доработку лучше делать в расширении конфигурации.
  • ❌ Вычислять границу один раз, а потом удалять элементы в прямом цикле. Граница становится неверной после первого удаления.

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

Частые вопросы об ошибке с индексом массива

Чем индекс отличается от номера строки в табличной части?
Номер строки (НомерСтроки) начинается с 1, индекс — с 0. Строке с номером 5 соответствует индекс 4. Путаница этих величин — частая причина ошибки.
Почему в одной базе ошибка есть, а в другой с той же обработкой нет?
Различаются данные. Код не проверяет размер коллекции, и в одной базе нужный элемент есть, а в другой его нет: меньше строк, пустая табличная часть, другое число колонок в файле.
Можно ли отключить вывод этой ошибки?
Нет. Это исключение времени выполнения, и платформа прерывает операцию. Можно лишь перехватить его в коде через Попытка … Исключение, но это оправдано только при разборе внешних данных.
Что делать, если ошибка в обработке, у которой нет исходного кода?
Если внешняя обработка защищена, исправить её может только автор. Передайте ему полный текст ошибки и пример данных. Пока исправления нет, проверьте, не помогает ли подготовка исходных данных: заполненные табличные части, корректный файл.
Бывает ли эта ошибка в типовой конфигурации без доработок?
Бывает редко. Если путь в тексте ошибки ведёт в типовой модуль и база не изменялась, проверьте, установлен ли актуальный релиз конфигурации, и сообщите о сбое разработчику с примером данных.