Исключение ArgumentOutOfRangeException с текстом «Длина не может быть меньше нуля. Имя параметра: length» возникает в .NET-приложениях, когда в метод Substring или аналогичную строковую операцию передаётся отрицательное значение длины. Чаще всего виновник — выражение вида str.Substring(0, str.IndexOf(ch)), где символ-разделитель в строке не найден, и IndexOf возвращает -1.
Ошибка проявляется внезапно: код может месяцами работать на «правильных» данных и упасть на первой же строке, где ожидаемый разделитель отсутствует. Ниже разберём, как локализовать проблемное место, какие сценарии приводят к отрицательной длине и как исправить код без костылей.
Что означает это исключение
Сообщение «Length cannot be less than zero. Parameter name: length» — это локализованный текст исключения ArgumentOutOfRangeException, которое .NET выбрасывает при передаче недопустимого аргумента. Имя параметра length указывает, что отрицательным оказался именно аргумент длины, а не стартовый индекс.
Типичные методы, где возникает эта ошибка:
- 🔧
String.Substring(startIndex, length)— самый частый источник; - 📏
String.Remove(startIndex, count)при отрицательномcount; - ✂️ Конструкторы и методы работы с массивами, принимающие длину сегмента;
- 📂 Пользовательские методы, внутри которых вызывается одна из перечисленных операций.
Обратите внимание: исключение выбрасывается в момент вызова метода, поэтому в трассировке стека всегда видно точную строку кода, где произошёл сбой.
Классический сценарий: Substring вместе с IndexOf
Самая распространённая причина — комбинация IndexOf и Substring без проверки результата поиска. Метод IndexOf возвращает -1, если подстрока не найдена, и это значение напрямую попадает в параметр длины.
string line = "ключ=значение";
int pos = line.IndexOf('=');
string key = line.Substring(0, pos); // упадёт, если '=' нет
Если в line нет символа =, переменная pos станет равна -1, и вызов Substring(0, -1) выбросит именно то исключение, которое вы видите. Такое случается при разборе конфигурационных файлов, CSV-строк, ответов внешних сервисов и пользовательского ввода — везде, где формат данных не гарантирован.
Ошибка «длина не может быть меньше нуля» почти всегда означает, что IndexOf или LastIndexOf вернул -1, а результат не был проверен перед передачей в Substring.
Как найти проблемное место в коде
Первым делом откройте трассировку стека (stack trace) — она содержит имя метода и номер строки, где выброшено исключение. Если приложение логирует ошибки, ищите запись с типом System.ArgumentOutOfRangeException.
Полезный порядок действий:
- 🔍 Найдите в стеке верхний фрейм, относящийся к вашему коду, а не к библиотекам .NET;
- 🧭 Проверьте все вызовы
Substring,RemoveиIndexOfв этом методе; - 🧪 Поставьте точку останова и посмотрите фактическое значение строки и вычисленной длины;
- 📋 Сохраните входные данные, на которых падает код, — они понадобятся для проверки исправления.
⚠️ Внимание: если ошибка возникает только у части пользователей или периодически, проблема почти наверняка во входных данных, а не в логике. Не спешите переписывать алгоритм — сначала зафиксируйте реальную строку, вызвавшую сбой.
Способы исправления
Правильное исправление — не подавление исключения через try-catch, а проверка индекса до вызова строковой операции. Минимальный безопасный вариант выглядит так:
int pos = line.IndexOf('=');
if (pos >= 0)
{
string key = line.Substring(0, pos);
}
Альтернативы в зависимости от задачи:
- ✂️
line.Split('=')— не падает при отсутствии разделителя, просто возвращает массив из одного элемента; - 🛡️ Проверка
line.Contains('=')перед извлечением части строки; - 🧩 Регулярные выражения с явной проверкой
Match.Successдля сложных форматов; - 📐 Метод-обёртка, который возвращает пустую строку или значение по умолчанию при некорректном входе.
☑️ Чек-лист исправления ошибки
Ошибка в чужом коде или библиотеке
Иногда исключение прилетает из сторонней библиотеки, формата файла или внутренностей фреймворка. В этом случае виноваты по-прежнему данные: библиотека пытается разобрать строку, которая не соответствует ожидаемому формату.
Что можно сделать без изменения чужого кода: проверьте, какие значения вы передаёте в библиотеку — пути к файлам, строки подключения, параметры конфигурации. Пустые значения, отсутствующие ключи в app.config / appsettings.json и неожиданные символы в путях — частые косвенные причины.
Пример
ошибка при чтении конфигурации:Если приложение читает строку вида "Server=host;Port=5432" и разбирает её через Substring по индексу '=', то отсутствие одного из параметров (например, строка обрезана в файле) приведёт к IndexOf = -1 и падению с ошибкой про length. Проверьте целостность конфигурационного файла и отсутствие пустых секций.
Профилактика: как не допустить повторения
Чтобы ошибка не возвращалась, встройте защиту на уровне архитектуры. Валидация входных данных на границе системы — файлы, сетевые ответы, пользовательский ввод — дешевле, чем отладка исключений в глубине логики.
Включите в проекте анализ nullable reference types (C# 8+) и обрабатывайте пустые строки явно — значительная часть подобных сбоев связана с null или String.Empty там, где ожидались данные.
Сравнение подходов к разбору строк:
| Подход | Падает при отсутствии разделителя | Когда применять |
|---|---|---|
| Substring + IndexOf без проверки | Да | Только при гарантированном формате |
| Substring + IndexOf с проверкой на -1 | Нет | Когда нужна часть строки до разделителя |
| Split | Нет | Простое разделение на части |
| Regex с Match.Success | Нет | Сложные или переменные форматы |
⚠️ Внимание: оборачивание падающего кода в пустой try-catch скрывает ошибку, но не решает её — приложение продолжит работать с некорректными данными, что может привести к более серьёзным сбоям дальше по логике.
Часто задаваемые вопросы
Почему ошибка появляется только на некоторых данных?
Потому что исключение выбрасывается лишь тогда, когда вычисленная длина становится отрицательной — например, когда разделитель в конкретной строке отсутствует. На «правильных» данных тот же код работает без сбоев.
Может ли ошибка возникать не из-за Substring?
Да. Любой метод, принимающий параметр длины — Remove, методы работы с массивами и сегментами, сторонние библиотеки — может выбросить это исключение. Смотрите трассировку стека, чтобы определить точный источник.
Что делать, если stack trace указывает на системную библиотеку?
Поднимитесь по стеку выше — до первого фрейма вашего кода. Почти всегда системный метод лишь реагирует на некорректный аргумент, переданный из приложения.
Поможет ли замена Substring на диапазоны C# (str[..pos])?
Нет, оператор диапазона также выбросит исключение при отрицательном или выходящем за границы индексе. Проверка результата IndexOf обязательна в любом случае.
Как предотвратить такие ошибки в командной разработке?
Помогают статический анализ кода, юнит-тесты на граничные случаи (пустая строка, строка без разделителя, строка из одного разделителя) и код-ревью с акцентом на обработку результатов IndexOf.