Index out of bounds of Array... when checking if its out of bounds of the array.

I keep getting the error “IndexOutOfRangeException: Index was outside the bounds of the array.”
The thing is: the line of code that is triggering this is the same line I’m using to ensure I have a valid result.

My code is simply: if (Pak.North[Frame] != null) which I am using to ensure that we have a valid Frame to reference before I pass on that reference. But yet, this is the very part of my code that is causing a problem.

So, what is the correct way to do this? How do I properly set up my code to check if there is a valid result before I try to use it?
(Because honestly, it is a very reasonable possibility that the Pak class I’m checking contains arrays that have not been set up yet.)

If Pak itself is null, you need to check if it’s null.
If Pak isn’t null, then you need to check the Length value to make sure you’re within the range.

You’re getting the error because Pak.North[Frame] is out of range. It’s not even that it’s null, it’s that the index doesn’t exist. Think of it like you have 10 chairs and I ask you to check if the 11th chair is occupied. You would come back and tell me there is no 11th chair, since you expect that their should be one.

So, you probably want to check if Frame < Pak.Length, and then if you want to know if it has a value assign to it, you can check that as well.

3 Likes

While @Brathnann is correct, it seems a lot of people do not properly understand what and array is or how it works. Accessing a certain element in an array is just about using the index as an offset into a region of memory that the array represents. In the old C / C++ days when using an index which is out of bounds it just means you’re going to read / write from / to the memory right next to the array memory. Reading data like that may just end up in garbage data returned in the best case, but could also lead to a memory segmentation fault if you try to read beyond the limits of the memory page. Writing to an out of bounds element would in the best case just hit an area of unused memory but most of the time would corrupt other unrelated data which would likely cause a crash or at least random bugs.

Most modern languages always apply a bounds check before accessing an element and if the index is out of bounds they throw an exception that would immediately terminate any further processing. That’s the point of an exception. Throwing an exception means the program has reached an exceptional state it can not continue safely. So the currently executed code is terminated and the execution continues in the closest exception handler (so the catch block of a try-catch statement). If no exception handler has been installed, the exception would bubble up the callstack and if the application itself does not handle the exception, the OS would terminate your application. This is generally called a crash. Unity does handle all exception on the callback level. So Unity calls the callbacks you defined (Start / Update / …). If an exception is thrown inside those callbacks that you don’t handle yourself, it would be catched by Unity. Unity just creates a log when that happens, ignores the exception and just continues doing its own business.

Exceptions should to be avoided at all cost. Not only are they expensive, they also break the normal flow of the program. So you must not use an invalid index into an array.

Yes, some dynamic interpreted scripting languages (like PHP) allow accessing invalid indices and provide a way to check for the validity later. Personally I think this is a horrible and confusing concept and so detached from what the CPU actually does.

edit:
Just to answer the question what is the correct way:
It depends ^^. In a zero knowledge world we would have to do

if (Pak != null && Pak.North != null && Frame>=0 && Frame < Pak.North.Length && Pak.North[Frame] != null){
    // yey, we can use "Pak.North[Frame]" here
}

or broken up into early exits in a method

if (Pak == null || Pak.North == null)
    return;
if (Frame < 0 || Frame >= Pak.North.Length)
    return;
if (Pak.North[Frame] == null)
    return;

In reality any unnecessary check is just additional code that will execute. Also you have to think about how you’re going to handle those cases. What exactly would you do if any of the above conditions is not true? Certain things can be assumed to be setup correctly. If they are not, you would get an exception while testing so you know you made a mistake and can fix the cause.

Of course certain things may depend on runtime data that may change (like your “Frame” variable). Here it may make sense to implement a check if you have a valid index or not. But again, that depends on the usecase.

Instead of trying to mitigate a problem by skipping certain code parts, it’s always better to solve the issue at the root. If your code wants to access a certain element, make sure the index is valid at the time the index is calculated / generated / altered. If there is the possibility that no valid index is possible, you have to catch this case early

2 Likes

In case you were curious, in this case the Pak is a public variable that I am setting up in the inspector. It contains a number of arrays of sprite references.
As such the errors I am trying to be prepared for are simple human errors where I fail to properly set up an object’s Pak. The most obvious/likely scenario is that I neglect to set it up entirely, but it is also possible that I set up an array with the wrong size, missing a value, etc.
That’s the concern I am checking for, because this isn’t a problem with the code I’m writing, it’s a potential problem with objects I am setting up down the road.

Sure and that’s totally fine. Though if Pak is a serializable class and North an ordinary array / List that is also serialized, it would be enough to just check the bounds as Pak as well as the array can’t really be null. The only case where that may be is when you create an instance dynamically using AddComponent. In that case no serialized data would be present. So a check that “Frame” is inside the bounds of the array would probably be enough. Though if the North array can contain null values, you may also do the null check after the bounds check. So this is usually enough:

if (Frame < 0 || Frame >= Pak.North.Length)
    throw new System.Exception($"Frame index is out of bounds. Has value "{Frame}" but should be between 0 and {Pak.North.Length}");
if (Pak.North[Frame] == null)
    throw new System.Exception($"The element with index {Frame} in the Pak.North array is null. Either assign an object, or remove the element");

The instance you are looking at might have that.

What about something that wipes out that list before you use it?

What about other instances in your scene that you might accidentally have placed?

NullReference NEVER CHANGES. The answer is relentlessly and remorselessly ALWAYS the same.

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null
  • Identify why it is null
  • Fix that

Same goes for index out of range:

Here are some notes on IndexOutOfRangeException and ArgumentOutOfRangeException:

http://plbm.com/?p=236

Steps to success:

  • find which collection it is (critical first step!)
  • find out why it has fewer items than you expect
  • fix whatever logic is making the indexing value exceed the collection
  • remember you might have more than one instance of this script in your scene/prefab

For live interactive debugging, use this approach:

You must find a way to get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://discussions.unity.com/t/700551 or this answer for Android: https://discussions.unity.com/t/699654

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

When in doubt, print it out!™