FX NOOKAI CODE LAB
Loading

MQL5 Array Out of Range Error: Causes and Fixes

By FXNook Lab team

An MQL5 array out of range error means your code tried to read or write an array element outside the array’s valid indexes. Find the failing line, compare its index with the array’s current size, and fix the boundary or data-loading assumption that made the index invalid. It is a runtime problem, not a compile error: the code can compile successfully and still fail when it runs.

What an array out of range error means

Array indexes in MQL5 start at zero. If a one-dimensional array contains five elements, its valid indexes are 0, 1, 2, 3, and 4. An attempt to access index 5, or index -1, is outside its bounds and can produce the runtime error.

The invalid access can be a read, such as value = prices[index], or a write, such as prices[index] = value. It can also happen inside a called function if that function receives an index or array size that does not match what its code expects. The compiler can validate syntax and types, but it generally cannot know what a variable index will be when an EA or indicator runs.

That distinction matters when diagnosing the problem. If MetaEditor reports a compile error, the source has a syntax, declaration, or type issue. If the program compiles but stops or logs an array bounds error during execution, inspect the exact array access and the values used at that moment.

Find the failing line and inspect the array size

Start with the runtime message rather than changing loop limits at random. The terminal’s Experts or Journal tab, or the Strategy Tester’s Journal, may show the program name and source line associated with the error. Open that line in MetaEditor and identify the array being accessed, its index expression, and any condition that is supposed to keep the index valid.

For a one-dimensional array, ArraySize() returns its current number of elements. If the size is 5, valid indexes run from zero through ArraySize(array) - 1. A size of zero means there is no valid element to access. For multidimensional arrays, use ArrayRange(array, dimension) when checking the length of a particular dimension; ArraySize() returns the total number of elements across the array.

Use the MetaEditor debugger to pause before the failing line. Set a breakpoint, run the EA or indicator under the debugger, then step through the code and inspect the index, the array size, and the values used to calculate both. In the Strategy Tester, reproduce the same symbol, timeframe, inputs, and relevant test conditions. A failure that appears only after a certain number of bars or on a particular tick often points to a loop boundary or a data-readiness assumption.

A useful temporary log can show the key values immediately before access:

PrintFormat("index=%d, size=%d", index, ArraySize(values));

Logging helps when the problem is intermittent or occurs in the tester. Keep the log close to the access being investigated so the reported index and size describe the same execution, not a later state after the array has changed.

Common causes and practical fixes

CauseHow it becomes an invalid accessPractical fix
Off-by-one loopA loop uses i <= ArraySize(values). On its final pass, i equals the size, which is not a valid index.For a loop that visits every element, use i < ArraySize(values). If the array is empty, the loop then runs zero times.
Empty or resized arrayCode assumes an element exists even though a dynamic array has not been populated, or it was resized to a smaller length.Inspect the current size after allocation, resizing, or data copying. Return or take another action when the required number of elements is unavailable.
Mismatched indexesAn index derived from one array, such as a rates array, is used with another array that has fewer elements.Check the size of the array actually being indexed. Keep related arrays aligned, or validate each array against the index independently.
Data has not loadedCode assumes price history or indicator-buffer values are ready before the terminal has supplied the requested data.Check the result of the data request, such as the count returned by CopyBuffer(), before using its output.
Wrong series directionCode assumes that index zero means the oldest value or newest value without checking how that array is indexed.Inspect the array’s series flag and use one clear indexing convention throughout the calculation.

These causes can overlap. For example, a loop may use the correct limit for a copied array that normally contains three values, but the copy may return only two. The loop’s limit then needs to reflect the number actually available, not the number the code expected.

Use an explicit bounds check

Before reading a one-dimensional array with a variable index, check that the index is non-negative and smaller than the current size. This does not replace fixing a faulty loop or data assumption, but it makes the condition visible and gives the code a safe way to handle missing data.

This MQL5 script shows the unsafe access first. The array has three elements, so index 3 is outside its valid range. The unsafe version compiles, but can trigger an array out of range error when it runs.

// MQL5: unsafe access
void OnStart()
{
   int values[3] = {10, 20, 30};
   int index = 3;

   Print(values[index]);
}

The safe version checks the current size before reading. In an EA or indicator, the same check belongs immediately before the access, using the array and index involved in that operation.

// MQL5: safe access
void OnStart()
{
   int values[3] = {10, 20, 30};
   int index = 2;
   int size = ArraySize(values);

   if(index < 0 || index >= size)
   {
      PrintFormat("Invalid index %d; array size is %d", index, size);
      return;
   }

   Print(values[index]);
}

For a loop through every element, the bound should normally be the array’s size, with a strict less-than comparison. If the algorithm deliberately needs a previous or next element, guard that operation separately. For example, accessing values[i - 1] requires i to be at least 1; accessing values[i + 1] requires i + 1 to be smaller than the size.

Series arrays and price-data indexing

A series array uses index zero for the newest element, and higher indexes refer to older elements. A non-series array uses index zero for the first element in its stored order. Do not assume every array has the same direction: an array you create, a price-data array, and an indicator buffer may be indexed differently unless you establish a consistent convention.

ArrayGetAsSeries(array) tells you whether the array is accessed as a series. The flag changes how indexes address the array; it does not mean you can safely use an index without checking the array’s size. For a dynamic, one-dimensional array that your code controls, ArraySetAsSeries(array, true) can set series-style indexing. Static arrays and multidimensional arrays have restrictions, so do not apply that function indiscriminately.

When an EA uses series indexing, index 0 commonly represents the current bar and index 1 the previous completed bar. A calculation that intends to use the previous bar but reads index 0 may be logically wrong even though it is in bounds. Conversely, code written for oldest-first indexing can select the wrong bar if the actual array is series-indexed. These are indexing-direction errors, not necessarily out of range errors, but the same assumptions often lead to invalid indexes when code mixes arrays.

Make the direction explicit when working with multiple arrays. If you use a bar index from one array to access another, confirm both arrays have enough elements at that index and that the indexes refer to the same bar. A matching numeric index does not by itself prove the arrays have matching sizes or ordering.

Check CopyBuffer results before reading

CopyBuffer() requests values from an indicator handle and returns the number of elements copied, or a negative result if the data could not be copied at that time. Indicator data may not be ready yet, especially shortly after creating a handle or when the required history has not been calculated. Requesting three values does not make it safe to read three unless the copy actually supplied three.

This MQL5 EA example creates a moving-average handle, requests three buffer values, and only reads the current value after confirming the full request succeeded. The destination is a dynamic array set to series indexing, so ma[0] addresses the newest copied value.

// MQL5 EA example
int maHandle = INVALID_HANDLE;

int OnInit()
{
   maHandle = iMA(_Symbol, PERIOD_CURRENT, 14, 0, MODE_SMA, PRICE_CLOSE);
   if(maHandle == INVALID_HANDLE)
      return INIT_FAILED;

   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   if(maHandle != INVALID_HANDLE)
      IndicatorRelease(maHandle);
}

void OnTick()
{
   double ma[];
   ArraySetAsSeries(ma, true);

   int copied = CopyBuffer(maHandle, 0, 0, 3, ma);
   if(copied != 3)
   {
      PrintFormat("CopyBuffer supplied %d of 3 requested values", copied);
      return;
   }

   double currentMa = ma[0];
   PrintFormat("Current moving average: %f", currentMa);
}

The check is against the requested count because this code uses indexes 0, 1, and 2 as the available set. If a calculation only needs one value, request and validate one value. If partial results are acceptable, compare the returned count with the minimum number of elements the calculation needs, then limit all later accesses to those elements.

Do not confuse a failed or partial copy with a successful array access. The copy result tells you how many values are available; the destination’s allocation alone does not prove the requested data arrived. Depending on the destination and request, an array may have space for values that were not copied, so use the return value as the authority for how much data you can process.

Debugging checklist for an EA or indicator

  1. Locate the failing access. Read the Experts, Journal, or tester log and open the reported source line. Identify the exact array expression, not just the nearest loop.
  2. Record the index and size. Inspect the index expression and call ArraySize() immediately before access. For multidimensional arrays, check the relevant dimension with ArrayRange().
  3. Verify every loop boundary. A loop over all elements usually stops when i < size, not when i <= size. Also inspect neighboring-element expressions such as i - 1 and i + 1.
  4. Account for resizing and empty data. Follow the code path that creates, resizes, fills, or clears the array. Make sure the access happens only after the array contains the required number of elements.
  5. Validate data-copy counts. For CopyBuffer(), use the returned count before indexing the destination. Apply the same principle to other functions that report how many values were obtained.
  6. Check indexing direction. Use ArrayGetAsSeries() when the direction is not established by your code. Keep the meaning of index zero consistent when matching price arrays, buffers, and calculations.
  7. Reproduce and step through the failure. Use the MetaEditor debugger or Strategy Tester with the relevant inputs and conditions. Step over the code that builds the index and inspect the array immediately before the failing operation.

Once the invalid access is fixed, test the boundary cases as well as the ordinary path: an empty array, the smallest expected history, the final loop iteration, and a data request that returns fewer values than requested. A clean compile does not prove runtime indexing is correct, so exercise the code in the debugger or tester before relying on the change.

If you need help tracing the cause in an EA or indicator, you can upload the code to FXNook Lab’s MQL4/MQL5 error-fixing page. The Lab compiles submitted code, identifies and fixes reported causes, then checks the result again; review the changed version against your intended indexing behavior before using it.

Questions

How do I find which array index is out of range in MQL5?

Start with the source line named in the terminal or Strategy Tester log, then inspect the index expression on that line. Use the MetaEditor debugger or a temporary PrintFormat log immediately before the access to record the index and ArraySize() value together.

Does MQL5 array indexing start at zero?

Yes. The first element of an array is at index 0, so an array of size N has valid indexes from 0 through N minus 1. A series array still starts at index 0, but that index refers to the newest element.

Can CopyBuffer cause an array out of range error?

Yes, if code reads more elements than CopyBuffer actually supplied, or uses indexes beyond the destination array’s valid range. Compare the function’s returned count with the number of values your calculation needs before reading the buffer.