System.IndexOutOfRangeException
An IndexOutOfRangeException is thrown when you use an index that is outside the bounds of an array. Arrays are zero-based, so an array with three elements has the indexes 0, 1 and 2. The message is Index was outside the bounds of the array.
It only applies to arrays. Collections such as List<T> throw an ArgumentOutOfRangeException for the same mistake, with a message that names the parameter.
Minimum version: >= 1.1 >= Core 1.0
Statistics
Common causes
The cause is always an index that is negative or not smaller than the length. These are the usual ways to end up there.
An off-by-one error in a loop
The last valid index is Length - 1. A loop condition that uses <= instead of < goes one step too far.
var names = new[] { "Ada", "Grace", "Linus" };
for (var i = 0; i <= names.Length; i++)
{
Console.WriteLine(names[i]); // IndexOutOfRangeException when i is 3
}
Use <, or better, a foreach loop that cannot go out of bounds:
var names = new[] { "Ada", "Grace", "Linus" };
foreach (var name in names)
{
Console.WriteLine(name);
}
Reading from an empty array
An array can be empty, for example when no command line arguments are passed or a query returns nothing. Index 0 does not exist then.
var items = Array.Empty<string>();
var first = items[0]; // IndexOutOfRangeException
Check the length first, or use a method that handles the missing element:
var items = Array.Empty<string>();
var first = items.Length > 0 ? items[0] : null;
var firstOrDefault = items.FirstOrDefault();
Fewer fields than expected
Data from files and users often has fewer parts than the code assumes. Splitting a line gives you only as many elements as there are separators.
var line = "Ada,1815";
var parts = line.Split(',');
var country = parts[2]; // IndexOutOfRangeException, there are only two parts
Check the number of parts, and report bad lines instead of crashing on them:
var line = "Ada,1815";
var parts = line.Split(',');
if (parts.Length < 3)
{
Console.WriteLine($"Skipping line with {parts.Length} fields.");
return;
}
var country = parts[2];
A negative index
An index that is calculated, for example index - 1 to get the previous element, becomes negative at the start of the array.
var values = new[] { 10, 20, 30 };
var index = 0;
var previous = values[index - 1]; // IndexOutOfRangeException, the index is -1
Check the lower bound too, or use an index from the end:
var values = new[] { 10, 20, 30 };
var index = 0;
var previous = index > 0 ? values[index - 1] : 0;
var last = values[^1];
How to fix it and prevent it
Use foreach when you do not need the index
A foreach loop visits every element and cannot go out of bounds. Use a for loop only when the index itself matters.
Check the bounds before you index
A condition that checks index >= 0 && index < array.Length is cheap and removes the exception. ElementAtOrDefault does the same and returns the default value when the element is missing.
var parts = "Ada,1815".Split(',');
if (parts.Length > 2)
{
Console.WriteLine(parts[2]);
}
var country = parts.ElementAtOrDefault(2) ?? "unknown";
Count from the end with the ^ operator
In C# 8 and later, array[^1] is the last element and array[^2] the one before it. It removes the Length - 1 calculation, which is where many off-by-one errors start.
var values = new[] { 10, 20, 30 };
var last = values[^1];
var secondToLast = values[^2];
How to find the bad index
The stack trace points to the line that indexed the array:
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at Shop.Services.Report.Last() in C:\src\Shop\Services\Report.cs:line 12
at Program.<Main>$(String[] args) in C:\src\Shop\Program.cs:line 4
Line 12 of Report.cs reads _names[_names.Length], which is one past the last element. The exception does not tell you which index or how long the array was, so add both to a log message or inspect them in the debugger. If a line indexes several arrays, split it up to see which one failed.
Should you catch it?
No. An IndexOutOfRangeException is a bug, and catching it hides the bug. Check the index, or validate the data, instead.
Catch it only at the edge of your application, where you log unexpected exceptions and return an error response.
Find IndexOutOfRangeException before your users do
elmah.io logs every unhandled exception in your .NET application with its stack trace and request details, groups identical errors and notifies you when a new one appears.
Start free trialRelated exceptions
- NullReferenceException is the other common array mistake, thrown when the array itself is null.
- ArgumentException is the base class of
ArgumentOutOfRangeException, which is what aList<T>throws for a bad index. - ArrayTypeMismatchException is thrown when you store the wrong type of element in an array.
Frequently asked questions
Why does List<T> throw ArgumentOutOfRangeException and not IndexOutOfRangeException?
Arrays are checked by the runtime and throw IndexOutOfRangeException. List<T> checks its own indexer and throws ArgumentOutOfRangeException with the parameter name index. The cause is the same.
Is an array index zero-based in .NET?
Yes. An array with N elements has the indexes 0 to N - 1. Arrays with other lower bounds are possible, but rare.
How do I get the last element of an array?
Use array[^1] in C# 8 and later, or array[array.Length - 1] after checking that the array is not empty.
Can I find out which index was used from the exception?
No. The exception only has the message. Log the index and the length where you index the array, or look at them in the debugger.
Let your AI agent track it down
Connect Claude Code, Cursor, VS Code or Visual Studio to the elmah.io MCP server and ask your agent to look into IndexOutOfRangeException for you. For example:
The agent reads the stack trace and request details from elmah.io, finds the code in your repository and proposes a fix. In Claude Code, add the server with one command:
claude mcp add --transport http --client-id claudecode elmahio https://mcp.elmah.io/mcp
The MCP server is included on every plan and is currently in beta. Set up the MCP server.
Further reading
YouTube videos
Answers from Stack Overflow
if (myReader["Additional"] != DBNull.Value)
{
ltlAdditional.Text = "contains data";
}
else
{
ltlAdditional.Text = "is null";
}
By Robert Durgin. Read the original answer on Stack Overflow.
There are two basic ways how to map bidirectional one-to-one association in NH. Let's say the classes look like this:
public class Setting
{
public virtual Guid Id { get; set; }
public virtual Student Student { get; set; }
}
public class Student
{
public virtual Guid Id { get; set; }
public virtual Setting Setting { get; set; }
}
Setting class is a master in the association ("aggregate root"). It is quite unusual but it depends on problem domain...
Primary key association
public SettingMap()
{
Id(x => x.Id).GeneratedBy.Guid();
HasOne(x => x.Student).Cascade.All();
}
public StudentMap()
{
Id(x => x.Id).GeneratedBy.Foreign("Setting");
HasOne(x => x.Setting).Constrained();
}
and a new setting instance should be stored:
var setting = new Setting();
setting.Student = new Student();
setting.Student.Name = "student1";
setting.Student.Setting = setting;
setting.Name = "setting1";
session.Save(setting);
Foreign key association
public SettingMap()
{
Id(x => x.Id).GeneratedBy.Guid();
References(x => x.Student).Unique().Cascade.All();
}
public StudentMap()
{
Id(x => x.Id).GeneratedBy.Guid();
HasOne(x => x.Setting).Cascade.All().PropertyRef("Student");
}
Primary key association is close to your solution. Primary key association should be used only when you are absolutely sure that the association will be always one-to-one. Note that AllDeleteOrphan cascade is not supported for one-to-one in NH.
EDIT: For more details see:
http://fabiomaulo.blogspot.com/2010/03/conform-mapping-one-to-one.html
http://ayende.com/blog/3960/nhibernate-mapping-one-to-one
By Jakub Linhart. Read the original answer on Stack Overflow.
You're accessing the list by different threads, but a list is not threadsafe:
You could lock the list with:
lock(listTotalCost)
listTotalCost.Add(temp.Value);
Or use Concurrent collections.
By Jeroen van Langen. Read the original answer on Stack Overflow.
With Dictionary<,> you have to lock both reading and writing. So both
lock( ConnectionList ) {
ConnectionList.Add( key, res );
}
and
lock( ConnectionList ) {
res = ConnectionList[ key ];
}
and
lock( ConnectionList ) {
int cnt = ConnectionList.Count;
}
and
lock( ConnectionList ) {
ConnectionList.Clear();
}
and
lock( ConnectionList ) {
foreach ( var kv in ConnectionList ) {
// Do things
}
}
and so on :-)
With ConcurrentDictionary<,> you don't need any locking, but note that the syntax is a little different than the one of the Dictionary<,>
By xanatos. Read the original answer on Stack Overflow.
I haven't used DataReaders for 3+ years, so I wanted to confirm my memory and found this. Anyway, for anyone who happens upon this post like I did and wants a method to test IsDBNull using the column name instead of ordinal number, and you are using VS 2008+ (& .NET 3.5 I think), you can write an extension method so that you can pass the column name in:
public static class DataReaderExtensions
{
public static bool IsDBNull( this IDataReader dataReader, string columnName )
{
return dataReader[columnName] == DBNull.Value;
}
}
Kevin
By Kevin Nelson. Read the original answer on Stack Overflow.
Source: Stack Overflow