Обращение к несуществующему элементу коллекции в 1С 8.3: поиск строки кода и устранение

· 9 мин

Содержание

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

Частое заблуждение — считать, что «сломалась база» и пора запускать тестирование и исправление. На практике в подавляющем числе случаев виновата конкретная строка в модуле: в доработке, внешней обработке, расширении или, реже, в типовой конфигурации на неожиданных данных. В платформе 8.3 текст сообщения обычно звучит как Индекс находится за границами диапазона, в поиске его называют по-разному, но смысл тот же.

Почему 1С выдаёт ошибку индекса: основные причины

Индексы коллекций в 1С 8.3 начинаются с нуля. У массива из 5 элементов последний индекс — 4, а Массив.ВГраница() вернёт именно 4. Любое обращение к индексу меньше нуля или больше ВГраница() даёт ошибку.

Типовые источники:

  • 🔢 Сдвиг на единицу. Цикл Для Сч = 0 По Массив.Количество() Цикл делает на один проход больше, чем нужно.
  • 🗑️ Удаление в прямом цикле. После удаления элемента коллекция короче, а счётчик продолжает расти до старой границы.
  • 📭 Пустой результат. Результат.Выгрузить()[0] падает, если запрос не нашёл ни одной строки.
  • ✂️ Разбор строки. СтрРазделить() вернул меньше частей, чем ждал программист: в строке нет разделителя или пустое поле.
  • 📦 Пакет запросов. Код берёт Результаты[4], а в пакете после правки осталось 4 запроса.
  • 📄 Внешние данные. В файле Excel или CSV строка короче остальных: колонок меньше, чем код пытается прочитать.
  • 🧩 Чужой код. Расширение или внешняя обработка написаны под старый релиз и ждут другой состав колонок, реквизитов или строк.

Объекты, на которых это встречается чаще всего:

КоллекцияКак обращаются по индексуБезопасная граница
МассивМассив[Индекс]от 0 до ВГраница()
Таблица значенийТЗ[Индекс], ТЗ.Получить(Индекс)от 0 до ТЗ.Количество() - 1
Табличная часть документаОбъект.Товары[Индекс]от 0 до Количество() - 1
Результаты пакетаЗапрос.ВыполнитьПакет()[Индекс]по числу запросов в тексте
Колонки таблицыТЗ.Колонки[Индекс]от 0 до Колонки.Количество() - 1

Обращение к отсутствующему ключу у структуры даёт другую ошибку, а соответствие по отсутствующему ключу возвращает Неопределено. Поэтому если в тексте именно «индекс», ищите обращение по номеру.

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

Как найти строку кода, которая вызывает ошибку индекса

Без точного места исправлять нечего. Порядок действий — от простого к сложному.

1. Прочитать подробный текст ошибки

В окне сообщения нажмите ссылку подробностей. Там будет стек вызовов вида:

{Документ.РеализацияТоваровУслуг.МодульОбъекта(214)}: Индекс находится за границами диапазона
{ОбщийМодуль.ПроведениеСервер.Модуль(1530)}

Первая строка — модуль и номер строки, где случился сбой. Ниже — кто его вызвал. Этого обычно достаточно программисту.

💡 Скопируйте полный текст в письмо или заявку целиком. Фраза «выскакивает ошибка индекса» без стека не даёт ничего.

2. Посмотреть журнал регистрации

Если пользователь закрыл окно, запись остаётся в журнале. В БП 3.0, ЗУП 3.1 и УТ 11 он открывается через Администрирование → Обслуживание → Журнал регистрации. Отберите события с уровнем «Ошибка» за нужный интервал и по пользователю. В комментарии события лежит тот же стек.

3. Поймать ошибку в отладчике

Для разработчика самый быстрый путь:

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

4. Сузить круг, если код недоступен

Пользователю без Конфигуратора помогает метод исключения:

  • 🧩 запустить то же действие с отключёнными расширениями (Администрирование → Печатные формы, отчеты и обработки → Расширения);
  • 📄 открыть ту же форму типовой командой, а не внешней обработкой;
  • 👤 повторить под другим пользователем;
  • 📅 повторить на другом документе или за другой период.

Если ошибка пропала после отключения расширения — проблема в нём.

Ошибки в коде с индексами и как их переписать

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

Граница цикла

Неправильно — лишний проход:

Для Сч = 0 По Массив.Количество() Цикл
    Обработать(Массив[Сч]);
КонецЦикла;

Правильно — граница через ВГраница(). У пустого массива она равна -1, и цикл просто не выполнится:

Для Сч = 0 По Массив.ВГраница() Цикл
    Обработать(Массив[Сч]);
КонецЦикла;

Если индекс в теле не нужен, используйте Для Каждого Элемент Из Массив Цикл — там выйти за границу невозможно.

Удаление элементов в цикле

Прямой цикл с удалением пропускает элементы и в конце обращается к индексу, которого уже нет. Удаляйте с конца:

Индекс = Массив.ВГраница();
Пока Индекс >= 0 Цикл
    Если НеНужен(Массив[Индекс]) Тогда
        Массив.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

Для таблицы значений и табличной части схема та же: обход от Количество() - 1 до 0.

Пустой результат запроса

Код Запрос.Выполнить().Выгрузить()[0].Сумма падает, как только запрос ничего не нашёл. Надёжнее через выборку:

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

Разбор строки на части

Части = СтрРазделить(СтрокаФИО, " ", Ложь);
Фамилия = ?(Части.Количество() > 0, Части[0], "");
Имя     = ?(Части.Количество() > 1, Части[1], "");
Отчество = ?(Части.Количество() > 2, Части[2], "");

Строка «Иванов Иван» без отчества даёт массив из двух элементов, и прямое Части[2] упало бы.

Пакет запросов

Не берите результат пакета по «магическому» номеру. После того как кто-то добавит временную таблицу в начало текста, Результаты[3] укажет на другой запрос или выйдет за пределы. Варианты:

  • 🔍 вынести нужный запрос последним и брать Результаты[Результаты.ВГраница()];
  • 📝 записать номер в переменную с комментарием рядом с текстом запроса и проверять Результаты.Количество() перед обращением.

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

Ошибка индекса при загрузке файлов и внешних данных

Загрузка из Excel , CSV, текстовых выгрузок банка и маркетплейсов — второй по частоте источник ошибки. Код читает строку, делит её на поля и обращается к полю по номеру.

Что ломает загрузку:

  • 📊 в файле удалили или добавили колонку, а обработка ждёт прежний порядок;
  • ↩️ в конце файла пустые строки, а код не пропускает их;
  • 🔣 в ячейке встретился разделитель (точка с запятой внутри названия товара), и строка разбилась на лишние или недостающие поля;
  • 📑 данные лежат не на первом листе, а код читает первый.

Безопасный шаблон для текстовой загрузки:

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

Так загрузка не обрывается на всём файле, а сообщает номер проблемной строки. Пользователь правит её и загружает повторно.

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

Обмены и интеграции

В обменах через правила конвертации и в интеграциях с сайтом картина похожая: приходит пакет, где у объекта меньше строк табличной части или нет ожидаемого элемента. Смотрите протокол обмена: в нём указан объект, на котором прервалась загрузка. Исправление — на стороне отправителя (полнота выгрузки) или в правилах (проверка количества перед обращением).

Когда виноваты база или платформа

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

  1. Релиз конфигурации. Сравните его с актуальным. Ошибки индекса в типовом коде на редких данных исправляют в следующих релизах, а описание исправлений есть в документации к обновлению.
  2. Версия платформы. Конфигурация требует номер платформы не ниже указанного в её описании. На старой платформе часть механизмов работает некорректно.
  3. Кэш клиента. Закройте все сеансы 1С на компьютере пользователя и запустите базу с параметром /ClearCache в дополнительных параметрах запуска. Другой вариант — удалить папки кэша в %APPDATA%\1C\1cv8 и %LOCALAPPDATA%\1C\1cv8 при закрытой программе.
  4. Конфигурация базы данных. Если в Конфигураторе основная конфигурация отличается от конфигурации базы данных, выполните Конфигурация → Обновить конфигурацию базы данных. Нужен монопольный доступ.
  5. Целостность данных. Тестирование и исправление: Администрирование → Тестирование и исправление в Конфигураторе. Для файловой базы есть ещё утилита chdbfl.exe в папке bin платформы; она работает только с закрытой базой.

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

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

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

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

Профилактика держится на нескольких привычках разработчика и пары правил для администратора.

Для разработчика:

  • ✅ перебирать коллекции через Для Каждого, если индекс не нужен;
  • ✅ для доступа по номеру проверять Количество() или ВГраница() прямо перед обращением;
  • ✅ искать строку таблицы через Найти() или НайтиСтроки() вместо расчёта номера;
  • ✅ первую строку результата запроса получать через Выбрать() и Следующий();
  • ✅ при разборе внешних файлов считать поля в каждой строке и пропускать неполные с сообщением;
  • ✅ в обработчике Попытка … Исключение писать подробности ошибки в журнал регистрации, а не глотать её молча.

Для администратора и ответственного за базу:

  • 🧪 проверять внешние обработки и расширения на копии базы после каждого обновления релиза;
  • 📋 вести список доработок с указанием, под какой релиз они написаны;
  • 📨 требовать от подрядчика проверку на пустых данных: пустой документ, пустой отбор, файл без строк.

Конструкция Попытка … Исключение — не лекарство. Если обернуть ей обращение по индексу и ничего не делать в блоке исключения, документ проведётся с неполными движениями, а ошибку никто не увидит.

Частые вопросы

Можно ли исправить ошибку индекса без программиста?
Если ошибка в расширении или внешней обработке — да, временно: отключите расширение или используйте типовую команду. Если она в модуле конфигурации, нужна правка кода.
Почему ошибка появилась только сейчас, хотя обработка работала годами?
Изменились данные: пришёл пустой документ, строка без отчества, файл с новой колонкой. Код годами получал «удобные» данные и не проверял границы.
Поможет ли обновление платформы?
Только если ошибка в самой платформе или конфигурация требует более новую версию. Ошибку в прикладном коде новая платформа не исправит.
Почему индекс с нуля, а номер строки в табличной части с единицы?
НомерСтроки — реквизит строки для пользователя, он начинается с 1. Индекс в коллекции начинается с 0. Путаница между ними даёт сдвиг на единицу.
Что происходит с документом, на котором выпала ошибка?
Действие не выполнено: при проведении транзакция откатывается, и движения не записываются. Исправьте причину и проведите документ заново.