diff --git a/django/contrib/postgres/fields/array.py b/django/contrib/postgres/fields/array.py
index 9a1e3c286b..390a55a86d 100644
--- a/django/contrib/postgres/fields/array.py
+++ b/django/contrib/postgres/fields/array.py
@@ -7,8 +7,9 @@ from django.core import checks, exceptions
 from django.db.models import Field, IntegerField, Transform
 from django.db.models.lookups import Exact, In
 from django.utils import six
-from django.utils.translation import string_concat, ugettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
 
+from ..utils import prefix_validation_error
 from .utils import AttributeSetter
 
 __all__ = ['ArrayField']
@@ -133,14 +134,15 @@ class ArrayField(Field):
 
     def validate(self, value, model_instance):
         super(ArrayField, self).validate(value, model_instance)
-        for i, part in enumerate(value):
+        for index, part in enumerate(value):
             try:
                 self.base_field.validate(part, model_instance)
-            except exceptions.ValidationError as e:
-                raise exceptions.ValidationError(
-                    string_concat(self.error_messages['item_invalid'], e.message),
+            except exceptions.ValidationError as error:
+                raise prefix_validation_error(
+                    error,
+                    prefix=self.error_messages['item_invalid'],
                     code='item_invalid',
-                    params={'nth': i},
+                    params={'nth': index},
                 )
         if isinstance(self.base_field, ArrayField):
             if len({len(i) for i in value}) > 1:
@@ -151,14 +153,15 @@ class ArrayField(Field):
 
     def run_validators(self, value):
         super(ArrayField, self).run_validators(value)
-        for i, part in enumerate(value):
+        for index, part in enumerate(value):
             try:
                 self.base_field.run_validators(part)
-            except exceptions.ValidationError as e:
-                raise exceptions.ValidationError(
-                    string_concat(self.error_messages['item_invalid'], ' '.join(e.messages)),
+            except exceptions.ValidationError as error:
+                raise prefix_validation_error(
+                    error,
+                    prefix=self.error_messages['item_invalid'],
                     code='item_invalid',
-                    params={'nth': i},
+                    params={'nth': index},
                 )
 
     def formfield(self, **kwargs):
diff --git a/django/contrib/postgres/forms/array.py b/django/contrib/postgres/forms/array.py
index 4eaae3e295..ea466bc1ea 100644
--- a/django/contrib/postgres/forms/array.py
+++ b/django/contrib/postgres/forms/array.py
@@ -1,4 +1,5 @@
 import copy
+from itertools import chain
 
 from django import forms
 from django.contrib.postgres.validators import (
@@ -7,7 +8,9 @@ from django.contrib.postgres.validators import (
 from django.core.exceptions import ValidationError
 from django.utils import six
 from django.utils.safestring import mark_safe
-from django.utils.translation import string_concat, ugettext_lazy as _
+from django.utils.translation import ugettext_lazy as _
+
+from ..utils import prefix_validation_error
 
 
 class SimpleArrayField(forms.CharField):
@@ -38,16 +41,16 @@ class SimpleArrayField(forms.CharField):
             items = []
         errors = []
         values = []
-        for i, item in enumerate(items):
+        for index, item in enumerate(items):
             try:
                 values.append(self.base_field.to_python(item))
-            except ValidationError as e:
-                for error in e.error_list:
-                    errors.append(ValidationError(
-                        string_concat(self.error_messages['item_invalid'], error.message),
-                        code='item_invalid',
-                        params={'nth': i},
-                    ))
+            except ValidationError as error:
+                errors.append(prefix_validation_error(
+                    error,
+                    prefix=self.error_messages['item_invalid'],
+                    code='item_invalid',
+                    params={'nth': index},
+                ))
         if errors:
             raise ValidationError(errors)
         return values
@@ -55,32 +58,32 @@ class SimpleArrayField(forms.CharField):
     def validate(self, value):
         super(SimpleArrayField, self).validate(value)
         errors = []
-        for i, item in enumerate(value):
+        for index, item in enumerate(value):
             try:
                 self.base_field.validate(item)
-            except ValidationError as e:
-                for error in e.error_list:
-                    errors.append(ValidationError(
-                        string_concat(self.error_messages['item_invalid'], error.message),
-                        code='item_invalid',
-                        params={'nth': i},
-                    ))
+            except ValidationError as error:
+                errors.append(prefix_validation_error(
+                    error,
+                    prefix=self.error_messages['item_invalid'],
+                    code='item_invalid',
+                    params={'nth': index},
+                ))
         if errors:
             raise ValidationError(errors)
 
     def run_validators(self, value):
         super(SimpleArrayField, self).run_validators(value)
         errors = []
-        for i, item in enumerate(value):
+        for index, item in enumerate(value):
             try:
                 self.base_field.run_validators(item)
-            except ValidationError as e:
-                for error in e.error_list:
-                    errors.append(ValidationError(
-                        string_concat(self.error_messages['item_invalid'], error.message),
-                        code='item_invalid',
-                        params={'nth': i},
-                    ))
+            except ValidationError as error:
+                errors.append(prefix_validation_error(
+                    error,
+                    prefix=self.error_messages['item_invalid'],
+                    code='item_invalid',
+                    params={'nth': index},
+                ))
         if errors:
             raise ValidationError(errors)
 
@@ -159,18 +162,20 @@ class SplitArrayField(forms.Field):
         if not any(value) and self.required:
             raise ValidationError(self.error_messages['required'])
         max_size = max(self.size, len(value))
-        for i in range(max_size):
-            item = value[i]
+        for index in range(max_size):
+            item = value[index]
             try:
                 cleaned_data.append(self.base_field.clean(item))
-                errors.append(None)
             except ValidationError as error:
-                errors.append(ValidationError(
-                    string_concat(self.error_messages['item_invalid'], ' '.join(error.messages)),
+                errors.append(prefix_validation_error(
+                    error,
+                    self.error_messages['item_invalid'],
                     code='item_invalid',
-                    params={'nth': i},
+                    params={'nth': index},
                 ))
                 cleaned_data.append(None)
+            else:
+                errors.append(None)
         if self.remove_trailing_nulls:
             null_index = None
             for i, value in reversed(list(enumerate(cleaned_data))):
@@ -183,5 +188,5 @@ class SplitArrayField(forms.Field):
                 errors = errors[:null_index]
         errors = list(filter(None, errors))
         if errors:
-            raise ValidationError(errors)
+            raise ValidationError(list(chain.from_iterable(errors)))
         return cleaned_data
diff --git a/django/contrib/postgres/utils.py b/django/contrib/postgres/utils.py
new file mode 100644
index 0000000000..1563149c7e
--- /dev/null
+++ b/django/contrib/postgres/utils.py
@@ -0,0 +1,30 @@
+from __future__ import unicode_literals
+
+from django.core.exceptions import ValidationError
+from django.utils.functional import SimpleLazyObject
+from django.utils.translation import string_concat
+
+
+def prefix_validation_error(error, prefix, code, params):
+    """
+    Prefix a validation error message while maintaining the existing
+    validation data structure.
+    """
+    if error.error_list == [error]:
+        error_params = error.params or {}
+        return ValidationError(
+            # We can't simply concatenate messages since they might require
+            # their associated parameters to be expressed correctly which
+            # is not something `string_concat` does. For example, proxied
+            # ungettext calls require a count parameter and are converted
+            # to an empty string if they are missing it.
+            message=string_concat(
+                SimpleLazyObject(lambda: prefix % params),
+                SimpleLazyObject(lambda: error.message % error_params),
+            ),
+            code=code,
+            params=dict(error_params, **params),
+        )
+    return ValidationError([
+        prefix_validation_error(e, prefix, code, params) for e in error.error_list
+    ])
diff --git a/tests/postgres_tests/test_array.py b/tests/postgres_tests/test_array.py
index 094a1e2235..e9cec6b5b5 100644
--- a/tests/postgres_tests/test_array.py
+++ b/tests/postgres_tests/test_array.py
@@ -507,16 +507,32 @@ class TestValidation(PostgreSQLTestCase):
         self.assertEqual(cm.exception.code, 'nested_array_mismatch')
         self.assertEqual(cm.exception.messages[0], 'Nested arrays must have the same length.')
 
+    def test_with_base_field_error_params(self):
+        field = ArrayField(models.CharField(max_length=2))
+        with self.assertRaises(exceptions.ValidationError) as cm:
+            field.clean(['abc'], None)
+        self.assertEqual(len(cm.exception.error_list), 1)
+        exception = cm.exception.error_list[0]
+        self.assertEqual(
+            exception.message,
+            'Item 0 in the array did not validate: Ensure this value has at most 2 characters (it has 3).'
+        )
+        self.assertEqual(exception.code, 'item_invalid')
+        self.assertEqual(exception.params, {'nth': 0, 'value': 'abc', 'limit_value': 2, 'show_value': 3})
+
     def test_with_validators(self):
         field = ArrayField(models.IntegerField(validators=[validators.MinValueValidator(1)]))
         field.clean([1, 2], None)
         with self.assertRaises(exceptions.ValidationError) as cm:
             field.clean([0], None)
-        self.assertEqual(cm.exception.code, 'item_invalid')
+        self.assertEqual(len(cm.exception.error_list), 1)
+        exception = cm.exception.error_list[0]
         self.assertEqual(
-            cm.exception.messages[0],
+            exception.message,
             'Item 0 in the array did not validate: Ensure this value is greater than or equal to 1.'
         )
+        self.assertEqual(exception.code, 'item_invalid')
+        self.assertEqual(exception.params, {'nth': 0, 'value': 0, 'limit_value': 1, 'show_value': 0})
 
 
 class TestSimpleFormField(PostgreSQLTestCase):
@@ -538,6 +554,27 @@ class TestSimpleFormField(PostgreSQLTestCase):
             field.clean('a,b,')
         self.assertEqual(cm.exception.messages[0], 'Item 2 in the array did not validate: This field is required.')
 
+    def test_validate_fail_base_field_error_params(self):
+        field = SimpleArrayField(forms.CharField(max_length=2))
+        with self.assertRaises(exceptions.ValidationError) as cm:
+            field.clean('abc,c,defg')
+        errors = cm.exception.error_list
+        self.assertEqual(len(errors), 2)
+        first_error = errors[0]
+        self.assertEqual(
+            first_error.message,
+            'Item 0 in the array did not validate: Ensure this value has at most 2 characters (it has 3).'
+        )
+        self.assertEqual(first_error.code, 'item_invalid')
+        self.assertEqual(first_error.params, {'nth': 0, 'value': 'abc', 'limit_value': 2, 'show_value': 3})
+        second_error = errors[1]
+        self.assertEqual(
+            second_error.message,
+            'Item 2 in the array did not validate: Ensure this value has at most 2 characters (it has 4).'
+        )
+        self.assertEqual(second_error.code, 'item_invalid')
+        self.assertEqual(second_error.params, {'nth': 2, 'value': 'defg', 'limit_value': 2, 'show_value': 4})
+
     def test_validators_fail(self):
         field = SimpleArrayField(forms.RegexField('[a-e]{2}'))
         with self.assertRaises(exceptions.ValidationError) as cm:
@@ -648,3 +685,12 @@ class TestSplitFormField(PostgreSQLTestCase):
                 </td>
             </tr>
         ''')
+
+    def test_invalid_char_length(self):
+        field = SplitArrayField(forms.CharField(max_length=2), size=3)
+        with self.assertRaises(exceptions.ValidationError) as cm:
+            field.clean(['abc', 'c', 'defg'])
+        self.assertEqual(cm.exception.messages, [
+            'Item 0 in the array did not validate: Ensure this value has at most 2 characters (it has 3).',
+            'Item 2 in the array did not validate: Ensure this value has at most 2 characters (it has 4).',
+        ])