Разработка и Конфигурация · 12 мин
Индекс за пределами массива в 1С: как найти и исправить ошибку
Ошибка «Индекс находится за пределами массива» в 1С: почему возникает, как найти строку кода, исправить обращение к массиву, таблице значений и строке. Примеры кода и проверки.
Ошибка «Индекс находится за пределами массива» — одна из самых частых проблем, с которой сталкиваются разработчики и пользователи 1С. Она означает, что код пытается обратиться к элементу коллекции по номеру, которого в этой коллекции нет: например, к шестому элементу массива, в котором всего пять элементов. Платформа 1С нумерует элементы с нуля, поэтому последний допустимый индекс всегда на единицу меньше количества элементов.
Ошибка возникает не только при работе с массивами. Тот же текст появляется при обращении к таблице значений, строке табличной части, коллекции строк результата запроса и даже при обращении к символу строки по индексу. Поэтому первый шаг — понять, к какой именно коллекции идёт обращение, а уже потом искать причину выхода за границы.
Ниже разобраны типовые сценарии: где искать проблемное место, как исправить код, какие проверки добавить, чтобы ошибка не повторялась, и что делать, если ошибка возникает в типовой конфигурации, где код менять нельзя или нежелательно.
Что означает ошибка и почему она возникает
Встроенный язык 1С использует нумерацию с нуля. Если массив содержит 10 элементов, допустимые индексы — от 0 до 9. Обращение Массив[10] вызовет ошибку. Аналогично для таблицы значений с тремя строками обращение ТЗ[3] приведёт к падению, потому что строки имеют индексы 0, 1 и 2.
Типовые причины выхода за границы:
- цикл со счётчиком, в котором верхняя граница равна количеству элементов, а не количеству минус один;
- обращение к первому элементу коллекции, которая оказалась пустой (например, запрос ничего не вернул);
- разбор строки функцией
СтрРазделитьили её аналогами с последующим обращением к элементу, которого нет; - изменение коллекции внутри цикла: удаление элементов сдвигает индексы, и счётчик «уезжает» за границу;
- обращение к строке табличной части по сохранённому индексу после того, как строки были удалены или отсортированы.
Отдельный случай — обращение к символу строки: конструкция вида Строка[Позиция] в 1С также проверяет границы, и при выходе за длину строки возникает та же ошибка. Это часто встречается при посимвольном разборе номенклатурных кодов, штрихкодов и файлов обмена.
Как найти место ошибки
Когда ошибка возникает у пользователя в рабочей базе, первый источник информации — окно сообщения об ошибке. В нём указан модуль и, как правило, строка кода. Если конфигурация закрыта или поставляется без исходных текстов, сообщение покажет хотя бы объект и метод, что сузит поиск.
Если вы разработчик и ошибка воспроизводится, включите отладку: запустите конфигуратор в режиме отладки, поставьте точку останова на строке из сообщения и повторите действие. В момент остановки проверьте в табло значения: размер коллекции (Массив.Количество()) и текущее значение индекса. Почти всегда сразу видно, что индекс больше допустимого или коллекция пуста.
Когда ошибка плавающая и возникает только при определённых данных, полезно временно обернуть подозрительный участок в попытку и записать в журнал регистрации контекст: размер коллекции, значение счётчика, ключевые реквизиты обрабатываемого документа. Это позволит поймать условия, при которых логика ломается, не останавливая работу пользователей.
- 1Зафиксируйте точный текст ошибки и номер строки из сообщения.
- 2Откройте указанный модуль в конфигураторе и найдите обращение к коллекции по индексу.
- 3В отладчике проверьте Количество() элементов и значение индекса в момент ошибки.
- 4Определите, почему коллекция не содержит ожидаемый элемент: пустой запрос, фильтр, удаление строк.
- 5Исправьте логику и повторите сценарий на тех же данных.
Типовые исправления в коде
Проверка границ перед обращением
Самое надёжное исправление — явная проверка перед обращением к элементу. Например, вместо безусловного ПерваяСтрока = Результат[0] используйте проверку на пустоту коллекции. Это особенно важно после выборок из запросов: запрос вполне может ничего не вернуть, и код должен корректно обрабатывать эту ситуацию.
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Значение = Выборка.Сумма;
Иначе
Значение = 0; // данных нет — задаём поведение по умолчанию
КонецЕсли;
Цикл со счётчиком без выхода за границу
Классическая ошибка — цикл от 0 до Количество() вместо Количество() − 1. Правильный вариант:
Для Инд = 0 По Массив.Количество() - 1 Цикл
Сообщить(Массив[Инд]);
КонецЦикла;
Однако в большинстве случаев цикл со счётчиком вообще не нужен. Цикл Для Каждого Элемент Из Массив Цикл полностью исключает ошибку выхода за границы и делает код читаемее. Индексный цикл оправдан только тогда, когда нужен сам номер элемента или обход в обратном порядке.
Удаление элементов в цикле
Если внутри цикла удаляются элементы коллекции, обход нужно вести с конца — от большего индекса к меньшему. Тогда удаление текущего элемента не влияет на индексы ещё не обработанных:
Для Инд = 0 По ТЗ.Количество() - 1 Цикл
Строка = ТЗ[ТЗ.Количество() - 1 - Инд];
Если Строка.Пометка Тогда
ТЗ.Удалить(Строка);
КонецЕсли;
КонецЦикла;
Разбор строки с разделителями
При разборе строк через СтрРазделить (или самописные аналоги в старых конфигурациях) нельзя предполагать фиксированное число частей. Если входные данные приходят из файла или от пользователя, всегда проверяйте Части.Количество() перед обращением к Части[1], Части[2] и так далее.
Ошибка в типовой конфигурации: что делать пользователю
Если ошибка возникает в типовой конфигурации при штатных действиях — проведении документа, формировании отчёта, обмене данными — причина чаще всего не в коде платформы, а в данных или в доработках. Первым делом проверьте, есть ли в конфигурации расширения и внешние обработки: отключите их по очереди и повторите действие. Значительная доля «типовых» ошибок на практике оказывается следствием расширения, которое обращается к коллекции по индексу.
Второй частый источник — некорректные данные. Например, документ с пустой табличной частью там, где алгоритм ожидает хотя бы одну строку, или элемент справочника с пустым обязательным реквизитом, который потом разбирается по частям. Попробуйте воспроизвести ошибку на копии базы и методом исключения найти конкретный объект, на котором она возникает.
Третий шаг — обновление. Ошибки такого рода регулярно исправляются в релизах конфигураций. Если база давно не обновлялась, проверьте, воспроизводится ли проблема на актуальной версии на копии. Обновление выполняйте только после создания резервной копии и желательно сначала на тестовой базе.
Профилактика: как писать код, чтобы ошибка не возникала
Несколько простых правил существенно снижают вероятность выхода за границы коллекции. Во-первых, предпочитайте Для Каждого циклам со счётчиком всюду, где не нужен сам индекс. Во-вторых, любое обращение по индексу к результату внешних данных — запросу, файлу, строке от пользователя — должно предваряться проверкой размера коллекции.
В-третьих, не храните индексы строк между вызовами. Если нужно вернуться к строке табличной части позже, сохраняйте ссылку на саму строку или её уникальный идентификатор, а не номер: сортировка, удаление или интерактивные действия пользователя делают сохранённый индекс недействительным.
В-четвёртых, при обмене данными и загрузке из файлов считайте формат входных данных ненадёжным по умолчанию. Любой разбор строки или массива из внешнего источника должен иметь ветку «данных меньше, чем ожидалось» с понятным сообщением пользователю вместо падения.
Как проверить результат исправления
Действие завершается без ошибки, результат корректен
Ошибка повторяется или данные обрабатываются частично
Код отрабатывает ветку «нет данных» без падения
Ошибка возникает на пустых данных
Нет новых записей об ошибке
Ошибка появляется на других объектах — причина не устранена полностью
Связанные операции работают как раньше
Исправление сломало смежную логику
Когда причина не в коде: данные, обмены, оборудование
Есть сценарии, где ошибка «индекс за пределами массива» — лишь симптом. Например, при обмене с сайтом или загрузке прайса файл пришёл в неожиданном формате: меньше колонок, другой разделитель, пустые строки. Код разбора падает, хотя раньше работал. В таких случаях чинить нужно источник данных или добавить валидацию формата перед разбором.
Похожая ситуация возникает с оборудованием и внешними компонентами: сканер вернул строку неожиданной длины, компонента вернула массив с другим числом элементов после обновления. Если ошибка появилась после обновления платформы, конфигурации или внешней компоненты — это важная подсказка: сравните поведение на прежней версии и проверьте, не изменился ли формат возвращаемых данных.
Наконец, ошибка может быть следствием прямых правок данных в обход логики программы: ручного изменения записей через внешние инструменты, прерванных обменов, восстановления из устаревших копий. Если в базе есть объекты с «битой» структурой данных, типовые алгоритмы могут падать на них. Тестирование и исправление информационной базы (с предварительной копией) помогает выявить такие повреждения.
Как выбрать действие
Часто задаваемые вопросы
Почему ошибка возникает, хотя цикл написан «Для Каждого»?
Значит, обращение по индексу происходит внутри цикла — например, код берёт «следующий» элемент по индексу текущего плюс один, или обращается к другой коллекции по номеру строки текущей. Также проверьте, не вызывается ли из цикла процедура, внутри которой есть индексное обращение.
Можно ли просто обернуть код в «Попытка... Исключение»?
Технически можно, но это маскирует проблему, а не решает её: данные будут обрабатываться частично или неправильно, и вы не узнаете об этом. Попытка уместна только как временная диагностическая мера с записью контекста в журнал регистрации, пока ищется настоящая причина.
Ошибка появляется только у одного пользователя. В чём дело?
Скорее всего, дело в данных, с которыми работает именно этот пользователь: его документы, настройки отборов, права (ограничение по RLS может делать выборку пустой там, где у других она непустая). Воспроизведите действие под его сеансом на копии базы и сравните состав данных.
Нумерация в 1С точно с нуля? А в запросах и табличных частях?
Да, массивы, строки таблиц значений, выборки и символы строк индексируются с нуля. Исключение по сути одно: функция СтрНайти и подобные возвращают позицию символа, начиная с 1, — смешение этих двух подходов в одном алгоритме само по себе частый источник ошибок.
Ошибка возникает в закрытом модуле типовой конфигурации. Что делать?
Код закрытого модуля изменить нельзя. Проверьте наличие расширений, корректность данных объекта, на котором возникает ошибка, и актуальность релиза. Если проблема воспроизводится на чистой актуальной конфигурации без доработок — зафиксируйте шаги воспроизведения и передайте их разработчику конфигурации или франчайзи.
Как быстро проверить, пуст ли массив, перед обращением к элементу?
Используйте условие Если Массив.Количество() > 0 Тогда перед обращением к Массив[0]. Для выборки из запроса вместо индексов используйте метод Следующий() — он сам вернёт Ложь, если строк нет, и это исключает выход за границы.
Что важно запомнить
Ошибка «Индекс находится за пределами массива» всегда означает обращение к несуществующему элементу: индекс меньше нуля или больше Количество() − 1. Локализуйте строку в отладчике, проверьте размер коллекции и значение индекса, добавьте проверку границ или замените цикл на «Для Каждого». В типовых конфигурациях сначала ищите причину в расширениях, данных и устаревшем релизе. Любые правки и обновления выполняйте только после резервной копии.