Индекс вышел за границы массива в 1С 8.3: найти строку кода и устранить сбой
Содержание
Ошибка «индекс за границами массива» в 1С означает одно: код обратился к элементу коллекции по номеру, которого в ней нет. Например, в массиве 3 элемента (индексы 0, 1, 2), а программа просит Массив[3]. Исправление — найти эту строку через подробный текст ошибки или отладчик и добавить проверку количества элементов перед обращением.
Типичная ситуация: бухгалтер нажимает «Провести» или «Заполнить», а на экране Индекс находится за границами диапазона. Вчера тот же документ проводился. Значит, данные стали другими: пустая табличная часть, строка без разделителя, на одну позицию меньше. Код к этому не готов.
Что означает сообщение и как оно выглядит в 1С 8.3
Платформа 1С:Предприятие 8.3 пишет дословно Индекс находится за границами диапазона. В поиске эту ошибку чаще ищут как «индекс за границами массива», но речь об одном и том же.
Ошибка возникает не только у массивов. Она появляется при обращении по индексу к любой индексируемой коллекции:
- 📦
МассивиФиксированныйМассив; - 📋
ТаблицаЗначенийи её строки:Таблица[5]; - 🧾 табличная часть документа или справочника:
Объект.Товары[0]; - 🔤 результат
СтрРазделить():Части[2]; - 🗂
СписокЗначений, коллекция колонок, коллекция строк дерева.
Главное правило, без которого ошибку не понять: индексы в 1С начинаются с нуля. У коллекции из N элементов последний индекс равен N − 1. Метод ВГраница() у массива возвращает именно этот последний индекс, а у пустого массива — -1.
| Коллекция | Элементов | Допустимые индексы | Последний индекс |
|---|---|---|---|
| Массив из 3 элементов | 3 | 0, 1, 2 | 2 |
| Пустая табличная часть | 0 | нет | обращаться нельзя |
СтрРазделить("А;Б", ";") | 2 | 0, 1 | 1 |
Почему индекс выходит за границы массива: пять причин
1. Ошибка на единицу в цикле
Самая частая причина в самописном коде. Цикл идёт до Количество(), а не до Количество() - 1:
Для Индекс = 0 По Массив.Количество() Цикл
Сообщить(Массив[Индекс]); // на последнем шаге индекс = Количество()
КонецЦикла;
2. Обращение к первой строке пустой коллекции
Код уверен, что строка есть: Объект.Товары[0].Номенклатура. Для документа без товаров это падение. Так же ломается Запрос.Выполнить().Выгрузить()[0], когда запрос ничего не вернул.
3. Удаление элементов в цикле со счётчиком
В 1С граница цикла Для … По … вычисляется один раз, при входе в цикл. Если внутри удалять элементы, коллекция укорачивается, а счётчик продолжает идти до старой границы. На последних шагах индекс указывает в пустоту.
4. Разбор строки с непредсказуемым форматом
Загрузка из файла или обмена: строка "Иванов;Пётр" разбирается в расчёте на три поля, а пришло два. СтрРазделить(Стр, ";")[2] сразу даёт ошибку. В типовых обработках загрузки это часто всплывает на одной «кривой» строке файла.
5. Рассинхрон двух коллекций
Код идёт по индексам одного массива и берёт по тем же индексам значения из другого. Пока массивы одинаковой длины, всё работает. Добавили элемент в один — второй отстаёт, и на последнем шаге индекс выходит за его пределы.
Как найти строку с ошибкой: три способа диагностики
Пока не известна строка кода, исправлять нечего. Начните с самого быстрого способа.
Способ 1. Подробный текст ошибки
В окне ошибки 1С 8.3 нажмите ссылку для подробностей. Появится текст вида:
{Документ.РеализацияТоваровУслуг.МодульОбъекта(214)}: Индекс находится за границами диапазона
В фигурных скобках — объект, модуль и номер строки. Ниже идёт стек: какие процедуры вызывали друг друга. Скопируйте этот текст целиком. Его достаточно, чтобы программист открыл модуль и перешёл к строке.
💡 Если в пути стоит имя расширения или внешней обработки, причина в доработке, а не в типовой конфигурации.
Способ 2. Отладчик с остановкой по ошибке
Способ для тех, у кого есть доступ к Конфигуратору:
- Откройте базу в Конфигураторе.
- Запустите отладку:
Отладка → Начать отладку(F5). - В Конфигураторе включите
Отладка → Остановка по ошибкеи отметьте остановку при любой ошибке. - Повторите действие в пользовательском режиме.
- Отладчик остановится ровно на проблемной строке.
Дальше откройте Отладка → Стек вызовов (Ctrl+Alt+C), чтобы понять, откуда пришёл вызов. Выделите переменную и нажмите Shift+F9: окно «Вычислить выражение» покажет Массив.Количество() и текущее значение индекса. Расхождение видно сразу.
В клиент-серверной базе серверный код отлаживается, только если сервер 1С разрешает отладку. Включение отладки на сервере требует перезапуска службы — это обрывает сеансы всех пользователей. Делайте это в нерабочее время или на копии базы.
Способ 3. Журнал регистрации
Если ошибку видел пользователь, а вы — нет, откройте журнал регистрации: Администрирование → Обслуживание → Журнал регистрации (в Конфигураторе — Администрирование → Журнал регистрации). Отберите события с уровнем «Ошибка» за нужное время и по пользователю. В записи будет тот же текст с модулем и строкой.
| Способ | Когда подходит | Что нужно |
|---|---|---|
| Подробный текст ошибки | Ошибка воспроизводится у пользователя | Ничего, только окно ошибки |
| Отладчик | Нужно увидеть значения переменных | Конфигуратор, права администратора |
| Журнал регистрации | Ошибка была раньше, повторить сложно | Права на просмотр журнала |
Исправление индекса за границами массива пошагово
Когда строка найдена, порядок действий такой.
Шаг 1. Проверьте данные
Сначала посмотрите на сам документ или файл. Пустая табличная часть, документ без строк, файл с неполной строкой — частый корень проблемы. Иногда достаточно заполнить данные правильно, и код не трогать.
Шаг 2. Определите, какой индекс и какая длина
В отладчике вычислите оба значения. Если индекс равен количеству — это ошибка на единицу. Если коллекция пустая — нужна проверка перед обращением. Если длина «внезапно» меньше — ищите удаление в цикле.
Шаг 3. Внесите исправление
| Ситуация | Исправление |
|---|---|
Цикл до Количество() | Граница Количество() - 1 или ВГраница() |
| Обход всех элементов | Цикл Для Каждого … Из … без индексов |
| Пустая коллекция | Проверка Количество() > 0 или Количество() = 0 |
| Удаление в цикле | Обратный цикл от последнего элемента |
| Разбор строки | Проверка числа частей после СтрРазделить() |
Шаг 4. Проверьте на копии
Повторите исходное действие на копии базы с теми же данными. Проверьте и граничные случаи: пустая таблица, одна строка, много строк.
В типовую конфигурацию на поддержке исправления лучше вносить через расширение, а не снимать конфигурацию с поддержки. Так правка переживёт обновление релиза.
Если ошибка в типовой конфигурации
Бывает, что в подробном тексте ошибки указан типовой модуль, а доработок в базе нет. Порядок такой:
- 🔎 Проверьте данные. Типовой код рассчитан на корректные данные, а битая или неполная информация в документе его ломает.
- 🔄 Сравните релиз конфигурации с актуальным. Подобные ошибки разработчики исправляют в новых релизах.
- 🧩 Отключите расширения и внешние обработки на копии базы и повторите действие. Если ошибка ушла, виновата доработка.
- 🛠 Запустите тестирование и исправление информационной базы на копии, если подозреваете повреждение данных.
Тестирование и исправление запускайте только после резервной копии. Оно требует монопольного режима: все пользователи должны выйти из базы.
Если ничего не помогло, отправьте подробный текст ошибки и номер релиза в поддержку вашего партнёра 1С или разработчику доработки. Текст со стеком вызовов экономит им несколько итераций переписки.
Примеры кода до и после исправления
Цикл с ошибкой на единицу
До:
Для Индекс = 0 По Массив.Количество() Цикл
Итог = Итог + Массив[Индекс];
КонецЦикла;
После:
Для Каждого Значение Из Массив Цикл
Итог = Итог + Значение;
КонецЦикла;
Если индекс всё же нужен, граница — Массив.ВГраница(). Для пустого массива это -1, и цикл Для Индекс = 0 По -1 не выполнится ни разу.
Первая строка табличной части
До:
Номенклатура = Объект.Товары[0].Номенклатура;
После:
Номенклатура = Неопределено;
Если Объект.Товары.Количество() > 0 Тогда
Номенклатура = Объект.Товары[0].Номенклатура;
КонецЕсли;
Удаление элементов в цикле
До:
Для Индекс = 0 По Массив.ВГраница() Цикл
Если Массив[Индекс] = 0 Тогда
Массив.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Граница вычислена один раз. Удалили один элемент — последний шаг обратится к несуществующему индексу.
После, обратный цикл:
Всего = Массив.Количество();
Для Сч = 1 По Всего Цикл
Индекс = Всего - Сч;
Если Массив[Индекс] = 0 Тогда
Массив.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Проверим на массиве из 4 элементов: индексы идут 3, 2, 1, 0. Удаление элемента с индексом 3 не сдвигает элементы 0–2, поэтому следующие обращения корректны.
Разбор строки из файла
До:
Части = СтрРазделить(СтрокаФайла, ";");
ИНН = Части[2];
После:
Части = СтрРазделить(СтрокаФайла, ";");
Если Части.Количество() < 3 Тогда
ТекстОшибки = СтрШаблон("Строка %1: ожидалось 3 поля, получено %2",
Формат(НомерСтроки, "ЧГ=0"), Формат(Части.Количество(), "ЧГ=0"));
Сообщить(ТекстОшибки);
Продолжить;
КонецЕсли;
ИНН = Части[2];
Код не падает на всём файле, а сообщает номер плохой строки и идёт дальше. Пример предполагает, что он стоит внутри цикла по строкам файла, где есть переменная НомерСтроки.
Результат запроса
До:
Цена = Запрос.Выполнить().Выгрузить()[0].Цена;
После:
Выборка = Запрос.Выполнить().Выбрать();
Цена = 0;
Если Выборка.Следующий() Тогда
Цена = Выборка.Цена;
КонецЕсли;
Выборка не требует индекса и не выгружает таблицу целиком, поэтому ещё и быстрее.
Чего не делать при исправлении
Несколько «исправлений», которые убирают сообщение, но оставляют проблему:
- ❌ Обернуть всё в
Попытка … Исключениес пустым обработчиком. Ошибка пропадёт, но документ проведётся с неполными данными, и никто не узнает почему. Если попытка нужна, хотя бы запишитеПодробноеПредставлениеОшибки(ИнформацияОбОшибке())в журнал регистрации. - ❌ Сдвинуть границу «на всякий случай» до
Количество() - 2. Последний элемент перестанет обрабатываться, и итоги разойдутся. - ❌ Править типовой модуль напрямую. Правка потеряется при обновлении или усложнит его. Используйте расширение.
- ❌ Исправлять в рабочей базе без проверки. Новая проверка может пропустить другую ветку кода. Сначала копия.
Как писать код без выхода за границы массива
Профилактика проще отладки. Несколько привычек снимают почти все случаи:
- ✅ Для обхода всех элементов используйте
Для Каждого. Индексы там не нужны, ошибиться в границе невозможно. - ✅ Перед
[0]всегда проверяйтеКоличество(). Пустые табличные части и пустые результаты запросов — нормальное состояние данных. - ✅ Удаляйте элементы обратным циклом или собирайте «что удалить» в отдельный массив и удаляйте после обхода.
- ✅ Данные извне (файлы, обмены, ответы сервисов) проверяйте на число полей до разбора.
- ✅ Не держите параллельные массивы. Удобнее одна таблица значений с колонками или структура в каждом элементе.
- ✅ Для поиска строки используйте
Найти()илиНайтиСтроки()с проверкой результата наНеопределеноили пустоту, а не перебор по индексу.
Частые вопросы
Почему ошибка появляется не у всех пользователей?
Чем ВГраница() отличается от Количество()?
Количество() возвращает число элементов, ВГраница() — индекс последнего. Для массива из 5 элементов это 5 и 4, для пустого — 0 и −1.Можно ли получить элемент массива без риска ошибки?
Получить() при неверном индексе тоже выдаёт ошибку. Безопасный путь — проверить индекс: Если Индекс <= Массив.ВГраница() Тогда.