ArrayStoreException in Java: Causes and How to Fix It

Learn why ArrayStoreException happens with covariant arrays, System.arraycopy() and toArray(), how to read its message, and how to fix and prevent it.

An Object[] variable pointing to a String[] array; storing a String passes the runtime check and storing an Integer throws ArrayStoreException

ArrayStoreException is an unchecked exception that the JVM throws when code stores a value in an array whose runtime element type cannot hold it, for example an Integer in an array created as String[]. The code compiles, because the variable has a wider type such as Object[], and the error shows up only when the store runs.

We meet the exception in code that passes arrays around as Object[] or Number[], and in JDK methods that store elements for us, such as System.arraycopy() and toArray(). The fix is almost always a type change, not a try-catch block.

The following example compiles without a warning and fails on the third line.

Object[] labels = new String[2];      // compiles, arrays are covariant
labels[0] = "draft";                  // fine, a String
labels[1] = 42;                       // ArrayStoreException: java.lang.Integer

Notice that the declared type Object[] accepts 42, but the array object is a String[]. We look at why Java allows the assignment, what the messages mean, the real-world sources of the exception, and the fixes.

1. Why the Compiler Lets the Bad Store Through

Java arrays are covariant. If String is a subtype of Object, the JLS makes String[] a subtype of Object[], so an Object[] variable can point to a String[]. The compiler checks every store against the variable’s type, and for an Object[] variable any object passes.

An Object[] variable pointing to a String[] array; storing a String passes the runtime check and storing an Integer throws ArrayStoreException
The compiler checks the variable type, while the JVM checks the real element type of the array on every store

The array object itself remembers its element type. On every store into an array of references, the JVM checks that the value fits that type, and if it does not, it throws ArrayStoreException before the array changes. A null value always passes, because null fits every reference type.

Integer[] ids = {1, 2};
Number[] numbers = ids;               // legal, Integer[] is a Number[]
numbers[0] = 7;                       // fine, an Integer
numbers[1] = 2.5;                     // ArrayStoreException: java.lang.Double
Object[] names = new String[1];
names[0] = null;                      // fine, null fits any reference type

Generics are invariant, so the same mistake with a List fails at compile time instead of at runtime. A List<String> is not a List<Object>, which is one reason to prefer collections over arrays in APIs, as the Java generics guide explains.

// does not compile: incompatible types: List<String> cannot be converted to List<Object>
List<Object> labels = new ArrayList<String>();

2. Reading the Exception Message

The message names the class of the value that did not fit, so java.lang.ArrayStoreException: java.lang.Double means some code tried to store a Double. The first line of the stack trace points to the store. To find the real cause, we look for the place where the array was created with a narrower type than the variable suggests.

System.arraycopy() uses longer messages that describe the two arrays. HotSpot on Java 25 prints these texts for the three typical cases.

java.lang.ArrayStoreException: arraycopy: type mismatch: can not copy int[] into long[]
java.lang.ArrayStoreException: arraycopy: type mismatch: can not copy int[] into object array[]
java.lang.ArrayStoreException: arraycopy: element type mismatch: can not cast one of the elements of java.lang.Object[] to the type of the destination array, java.lang.String

The wording of these messages comes from the JVM and is not part of the API, so we do not parse it in code. The exception type and the stack trace are what we act on.

3. Where ArrayStoreException Comes From in Real Code

Direct stores such as labels[1] = 42 are rare in production code. The exception mostly comes from library calls that store elements for us.

3.1. Methods That Take Object[] Parameters

Say a form library has a helper that fills empty slots with a placeholder. It takes an Object[] so it works with any array, and it stores an Integer 0. Called with an Integer[], it works, but a caller that passes a String[] gets the exception from inside the library.

static void fillBlanks(Object[] slots) {
    for (int i = 0; i < slots.length; i++) {
        if (slots[i] == null) {
            slots[i] = 0;
        }
    }
}
Integer[] counts = {5, null};
fillBlanks(counts);
Integer[] filled = counts;            // [5, 0]
String[] fields = {"name", null};
fillBlanks(fields);                   // ArrayStoreException: java.lang.Integer

Arrays.fill() has the same Object[] signature, so Arrays.fill(stringArrayAsObjects, 0) fails the same way.

3.2. System.arraycopy() Between Incompatible Arrays

The System.arraycopy() method takes its arrays as Object, so the compiler cannot check them. It throws ArrayStoreException for a primitive source and a reference destination, for two different primitive types, and for a reference element that does not fit the destination.

int[] raw = {1, 2};
long[] wide = new long[2];
System.arraycopy(raw, 0, wide, 0, 2);          // ArrayStoreException: arraycopy: type mismatch
Object[] mixed = {"a", "b", 3, "d"};
String[] dest = new String[4];
System.arraycopy(mixed, 0, dest, 0, 4);        // ArrayStoreException: arraycopy: element type mismatch
String[] partial = dest;                       // [a, b, null, null]

The last line shows a detail from the Javadoc. In the element-by-element case, the elements before the bad one are already copied, so the destination array is left half-filled. Code that retries the copy must reset or discard the destination array.

3.3. toArray() on Collections and Streams

Collection.toArray(T[]) and Stream.toArray(generator) create an array of the type we ask for and store every element in it. A List<Object> or a raw list filled from JSON or a database can contain a different type than we expect, and the conversion fails.

List<Object> row = new ArrayList<>(List.of("Lokesh", 37));
String[] cells = row.toArray(new String[0]);                       // ArrayStoreException
String[] values = Stream.of((Object) "a", 2).toArray(String[]::new);   // ArrayStoreException: java.lang.Integer

The safe version maps every element to the target type first, so a wrong value fails with a clear message, or it is converted on purpose. The guide on converting a List to an array covers the normal case.

List<Object> row = new ArrayList<>(List.of("Lokesh", 37));
String[] cells = row.stream().map(String::valueOf).toArray(String[]::new);   // [Lokesh, 37]

3.4. Arrays.copyOf() With a Different Array Type

The overload Arrays.copyOf(original, length, newType) copies an array into a new array of another type. Every element must fit the new element type, otherwise the method throws.

Object[] input = {"a", 1};
Object[] asStrings = Arrays.copyOf(input, 2, String[].class);      // ArrayStoreException
Object[] ok = Arrays.copyOf(new Object[] {"a", "b"}, 2, String[].class);
String type = ok.getClass().getSimpleName();                       // "String[]"

4. Fixing and Preventing ArrayStoreException

The real fix is to make the array’s element type match the values we store, so the exception cannot happen. In order of preference, we do the following.

  • Declare the variable with the exact array type, such as String[] instead of Object[], so the compiler rejects wrong stores.
  • Use a List<T> in method parameters and return types, because generics catch the mismatch at compile time.
  • Convert values to the target type before a toArray() call, as in section 3.
  • Create the array with the element type that the values need, for example Object[] when the values are mixed.

When a method must accept arrays of unknown type, it can check each value before the store. The check uses Class.isInstance(), which also accepts subtypes, whereas comparing getClass() with == rejects a subtype such as an Integer in a Number[].

static boolean tryStore(Object[] array, int index, Object value) {
    Class<?> elementType = array.getClass().getComponentType();
    if (value != null && !elementType.isInstance(value)) {
        return false;
    }
    array[index] = value;
    return true;
}
Number[] amounts = new Integer[2];
boolean stored = tryStore(amounts, 0, 10);       // true
boolean rejected = tryStore(amounts, 1, 9.99);   // false, a Double does not fit
Number[] result = amounts;                       // [10, null]

Catching ArrayStoreException is a last resort for code that receives arrays from plugins or reflection. A catch block hides the type mistake and leaves the array partly updated in the arraycopy() case, so we log it with the array type and fix the caller.

5. ArrayStoreException Compared With Similar Exceptions

ArrayStoreException extends RuntimeException and has existed since Java 1.0. Developers often confuse it with other runtime exceptions that involve arrays or types.

ExceptionThrown whenExample
ArrayStoreExceptionA value does not fit the array’s runtime element typeobjs[0] = 1 where objs is a String[]
ClassCastExceptionA cast names a type the object does not have(String) Integer.valueOf(1)
ArrayIndexOutOfBoundsExceptionThe index is negative or not less than lengthtwo[2] where two has length 2
NegativeArraySizeExceptionAn array is created with a negative lengthnew int[-1]
Object value = Integer.valueOf(1);
String text = (String) value;                  // ClassCastException
int[] two = new int[2];
int third = two[2];                            // ArrayIndexOutOfBoundsException

6. ArrayStoreException FAQs

Most questions about ArrayStoreException come from the gap between the compile-time check on the variable type and the runtime check on the array type.

6.1. Is ArrayStoreException checked or unchecked?

Unchecked. It extends RuntimeException, so methods do not declare it and the compiler does not force us to catch it.

6.2. Can ArrayStoreException happen with primitive arrays?

Not with normal stores, because the compiler rejects a double stored into an int[] without a cast. It happens only through System.arraycopy() between different primitive types, or between a primitive and a reference array.

6.3. Why do generics not throw ArrayStoreException?

Because generic types are invariant and checked at compile time, so a List<Object> variable cannot point to a List<String>. For the same reason, Java does not allow new T[] or new List<String>[10], since the runtime store check could not see the type argument.

6.4. Does Arrays.asList(array).toArray() still cause ArrayStoreException?

Not since Java 9. Before Java 9, Arrays.asList(stringArray).toArray() returned a String[] instead of an Object[] (JDK-6260652), so storing another type in the result threw. Since Java 9 the method returns an Object[].

6.5. Should we catch ArrayStoreException?

Rarely. The exception signals a type bug in our code, and the fix is a correct array or a List. We catch it only at a boundary that receives arrays we do not control, and we log the array type there.

7. Conclusion

ArrayStoreException comes from array covariance. A String[] can sit in an Object[] variable, so the compiler accepts any object, and the JVM rejects the store at runtime with the class name of the wrong value.

In real code, the exception comes from helpers with Object[] parameters, System.arraycopy(), toArray() calls and Arrays.copyOf() with a new type. Exact array types and List<T> move the check to compile time, and Class.isInstance() guards the rare code that must accept any array.

8. References

Happy Learning !!

Source Code on Github

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.