diff --git a/.gitignore b/.gitignore
index 5d1d33b..cfd4097 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,3 +94,7 @@ ENV/
 # Rope project settings
 .ropeproject
 .idea/
+
+# debug files
+debug.py
+app.py
diff --git a/.travis.yml b/.travis.yml
index fa1071d..99833f7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,6 @@
 language: python
 dist: focal
 python:
-  - "3.6"
   - "3.7"
   - "3.8"
   - "3.9"
diff --git a/flask_request_validator/exceptions.py b/flask_request_validator/exceptions.py
index 265c184..c4e658b 100755
--- a/flask_request_validator/exceptions.py
+++ b/flask_request_validator/exceptions.py
@@ -154,6 +154,14 @@ def __init__(self, errors: List[Any]) -> None:
         self.errors = errors
 
 
+class MissingJsonKeyError(RuleError):
+    def __init__(self, key: str) -> None:
+        self.key = key
+
+    def __str__(self) -> str:
+        return 'key is required'
+
+
 class RulesError(RequestError):
     def __init__(self, *args: RuleError):
         self.errors = args
diff --git a/flask_request_validator/nested_json.py b/flask_request_validator/nested_json.py
index c94f738..53ad359 100644
--- a/flask_request_validator/nested_json.py
+++ b/flask_request_validator/nested_json.py
@@ -4,7 +4,10 @@
     JsonError,
     RequiredJsonKeyError,
     JsonListItemTypeError,
-    RulesError, JsonListExpectedError, JsonDictExpectedError,
+    RulesError,
+    JsonListExpectedError,
+    JsonDictExpectedError,
+    MissingJsonKeyError,
 )
 from .rules import CompositeRule, AbstractRule
 
@@ -46,6 +49,17 @@ def _check_list_item_type(self, nested: 'JsonParam', value: Any):
         if isinstance(nested.rules_map, dict) and not isinstance(value, dict):
             raise JsonListItemTypeError()
 
+    def _is_missing_json_key(self, key: str, value: Dict, nested: 'JsonParam'):
+        rules = nested.rules_map.get(key)
+        if isinstance(rules, JsonParam) and not rules.required:
+            return
+
+        try:
+            if key not in value:
+                raise MissingJsonKeyError(key)
+        except MissingJsonKeyError as error:
+            raise RulesError(error)
+
     def _validate_list(
         self,
         value: Union[Dict, List],
@@ -101,18 +115,26 @@ def _validate_dict(
         errors: List[JsonError],
     ) -> Tuple[Any, List[JsonError], Dict[str, RulesError]]:
         err = dict()
-        for key, rules in nested.rules_map.items():
-            if key not in value:
-                continue
-            elif isinstance(rules, JsonParam):
-                new_val, errors = self.validate(value[key], rules, depth + [key], errors)
-                continue
 
+        for key, rules in nested.rules_map.items():
             try:
-                new_val = rules.validate(value[key])
-                value[key] = new_val
+                self._is_missing_json_key(key, value, nested)
             except RulesError as e:
                 err[key] = e
+                continue
+
+            key_value = value.get(key)
+            if isinstance(rules, JsonParam):
+                if key_value is None and not nested.rules_map[key].required:
+                    continue
+
+                new_val, errors = self.validate(key_value, rules, depth + [key], errors)
+            else:
+                try:
+                    new_val = rules.validate(key_value)
+                    value[key] = new_val
+                except RulesError as e:
+                    err[key] = e
 
         return value, errors, err
 
diff --git a/setup.py b/setup.py
index c4d10cd..08fe544 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
 
 setup(
     name='flask_request_validator',
-    version='4.2.1',
+    version='4.2.2',
     description='Flask request data validation',
     long_description=long_description,
     url='https://github.com/d-ganchar/flask_request_validator',
@@ -19,7 +19,6 @@
     classifiers=[
         'Development Status :: 5 - Production/Stable',
         'Framework :: Flask',
-        'Programming Language :: Python :: 3.6',
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
diff --git a/tests/test_nested_json.py b/tests/test_nested_json.py
index 49e2e9f..fe100b8 100644
--- a/tests/test_nested_json.py
+++ b/tests/test_nested_json.py
@@ -3,8 +3,8 @@
 
 from parameterized import parameterized
 
-from flask_request_validator.exceptions import *
 from flask_request_validator import JsonParam, Enum, CompositeRule, Min, Max, IsEmail, Number, MinLength
+from flask_request_validator.exceptions import *
 
 
 class TestJsonParam(unittest.TestCase):
@@ -59,62 +59,14 @@ class TestJsonParam(unittest.TestCase):
                 'meta': {'buildings': {'warehouses': {'small': {'count': 100, }, 'large': 0, }, }, },
             },
             [
-                [
-                    ['root', 'meta', 'buildings', 'warehouses', 'small'],
-                    {'count': [ValueMaxError]},
-                ],
-                [
-                    ['root', 'meta', 'buildings', 'warehouses'],
-                    {'large': [ValueMinError]},
-                ],
-                [
-                    ['root', 'meta'],
-                    {'description': RequiredJsonKeyError},
-                ],
-                [
-                    ['root'],
-                    {'street': [ValueEnumError], },
-                ],
+                "(['root', 'meta', 'buildings', 'warehouses', 'small'],"
+                " {'count': RulesError(ValueMaxError(99, True))}, False)",
+                "(['root', 'meta', 'buildings', 'warehouses'],"
+                " {'large': RulesError(ValueMinError(1, True))}, False)",
+                "(['root', 'meta'], {'description': RulesError(MissingJsonKeyError('description'))}, False)",
+                "(['root'], {'street': RulesError(ValueEnumError(('Jakuba Kolasa',)))}, False)",
             ],
         ),
-        # valid
-        (
-            DICT_SCHEMA,
-            {
-                'country': 'Belarus',
-                'city': 'Minsk',
-                'street': 'Jakuba Kolasa',
-                'meta': {
-                    'buildings': {
-                        'warehouses': {
-                            'small': {'count': 99, },
-                            'large': 1,
-                        },
-                    },
-                    'description': {
-                        'color': 'green',
-                    },
-                },
-            },
-            {},
-        )
-    ])
-    def test_dict(self, param: JsonParam, data, exp):
-        value, errors = param.validate(data)
-        for ix, json_error in enumerate(errors):  # type: list, JsonError
-            self.assertTrue(isinstance(json_error, JsonError))
-            exp_depth, epx_errors_map = exp[ix]  # type: list, dict
-            self.assertListEqual(json_error.depth, exp_depth)
-            for key, error in json_error.errors.items():
-                if isinstance(error, RulesError):
-                    self.assertEqual(len(error.errors), len(epx_errors_map))
-                    for ix_rule, rule_err in enumerate(error.errors):
-                        self.assertTrue(isinstance(rule_err, epx_errors_map[key][0]))
-                else:
-                    self.assertTrue(isinstance(error, epx_errors_map[key]))
-
-    @parameterized.expand([
-        # invalid
         (
             LIST_SCHEMA,
             {
@@ -138,31 +90,39 @@ def test_dict(self, param: JsonParam, data, exp):
                 },
             },
             [
-                [
-                    ['root', 'person', 'info', 'contacts', 'phones'],
-                    {
-                        2: JsonListItemTypeError,
-                        3: JsonListItemTypeError,
-                    },
-                ],
-                [
-                    ['root', 'person', 'info', 'contacts', 'networks'],
-                    {
-                        1: {'name': [ValueEnumError], },
-                        2: {'name': [ValueEnumError], },
-                    },
-                ],
-                [
-                    ['root', 'person', 'info', 'contacts', 'emails'],
-                    {
-                        0: JsonListItemTypeError,
-                        1: JsonListItemTypeError,
-                        2: [ValueEmailError],
-                    },
-                ],
+                "(['root', 'person', 'info', 'contacts', 'phones'], "
+                "{2: JsonListItemTypeError(False), 3: JsonListItemTypeError(False)}, True)",
+
+                "(['root', 'person', 'info', 'contacts', 'networks'], "
+                "{1: {'name': RulesError(ValueEnumError(('facebook', 'telegram')))}, "
+                "2: {'name': RulesError(ValueEnumError(('facebook', 'telegram')))}}, True)",
+
+                "(['root', 'person', 'info', 'contacts', 'emails'], "
+                "{0: JsonListItemTypeError(False), 1: JsonListItemTypeError(False), "
+                "2: RulesError(ValueEmailError())}, True)",
             ],
         ),
         # valid
+        (
+            DICT_SCHEMA,
+            {
+                'country': 'Belarus',
+                'city': 'Minsk',
+                'street': 'Jakuba Kolasa',
+                'meta': {
+                    'buildings': {
+                        'warehouses': {
+                            'small': {'count': 99, },
+                            'large': 1,
+                        },
+                    },
+                    'description': {
+                        'color': 'green',
+                    },
+                },
+            },
+            {},
+        ),
         (
             LIST_SCHEMA,
             {
@@ -184,26 +144,13 @@ def test_dict(self, param: JsonParam, data, exp):
             [],
         ),
     ])
-    def test_list(self, param: JsonParam, data, exp):
-        value, errors = param.validate(data)
-        self.assertEqual(len(exp), len(errors))
-        for err_ix, json_er in enumerate(errors):  # type: int, JsonError
-            exp_err = exp[err_ix]
-            exp_rule_err = exp_err[1]
-            self.assertListEqual(json_er.depth, exp_err[0])
-            self.assertEqual(len(exp_err[1]), len(json_er.errors))
-            for rules_ix, rules_err in exp_rule_err.items():
-                json_rules = json_er.errors[rules_ix]  # type: dict or list or RulesError
-                if isinstance(exp_rule_err[rules_ix], list):
-                    self.assertTrue(isinstance(json_rules, RulesError))
-                    for k, rule_err in enumerate(json_rules.errors):
-                        self.assertTrue(isinstance(rule_err, exp_rule_err[rules_ix][k]))
-                else:
-                    if isinstance(rules_err, dict):
-                        self.assertTrue(len(json_rules), len(rules_err))
-                    else:
-                        # RulesError
-                        self.assertTrue(isinstance(json_er.errors[rules_ix], rules_err))
+    def test_validate(self, param: JsonParam, data, exp):
+        value, errors = param.validate(deepcopy(data))
+        self.assertEqual(len(errors), len(exp))
+
+        for ix, json_error in enumerate(exp):  # type: int, List[list, dict]
+            str_error = str(errors[ix])
+            self.assertEqual(json_error, str_error)
 
     @parameterized.expand([
         (
@@ -245,28 +192,13 @@ def test_root_list_invalid(self):
             {'age': 15, 'name': 'good'},
         ])
 
-        self.assertEqual(1, len(errors))
-        self.assertTrue(isinstance(errors[0], JsonError))
-        error = errors[0]
-        self.assertListEqual(['root'], error.depth)
-        self.assertTrue(2, len(error.errors))
-        self.assertTrue(error.errors[0], 1)
-        self.assertTrue(error.errors[1], 2)
+        self.assertEqual(
+            "[JsonError(['root'], "
+            "{0: {'age': RulesError(NumberError())}, 1: "
+            "{'age': RulesError(NumberError()), 'name': RulesError(ValueMinLengthError(1))}}, True)]",
+            str(errors)
+        )
 
-        self.assertTrue(isinstance(error.errors[0]['age'].errors[0], NumberError))
-        self.assertTrue(isinstance(error.errors[1]['age'].errors[0], NumberError))
-        self.assertTrue(isinstance(error.errors[1]['name'].errors[0], ValueMinLengthError))
         # invalid type - dict instead list
         _, errors = param.validate({'age': 18, 'name': 'test'})
-        self.assertEqual(1, len(errors))
-        self.assertListEqual(['root'], errors[0].depth)
-        self.assertTrue(isinstance(errors[0], JsonListExpectedError))
-        # invalid type - nested string instead list
-        _, errors = param.validate([
-            {'age': 27, 'name': 'test'},
-            {'age': 15, 'name': 'good', 'tags': 'bad_type'},
-        ])
-
-        self.assertEqual(1, len(errors))
-        self.assertListEqual(['root', 'tags'], errors[0].depth)
-        self.assertTrue(isinstance(errors[0], JsonListExpectedError))
+        self.assertEqual("[JsonListExpectedError(['root'])]", str(errors))
diff --git a/tests/test_validator.py b/tests/test_validator.py
index 2356dcb..e7053e9 100755
--- a/tests/test_validator.py
+++ b/tests/test_validator.py
@@ -375,6 +375,21 @@ def home(valid: ValidRequest):
     return flask.jsonify({'json': valid.get_json()})
 
 
+@_app2.route('/issue/82', methods=['POST'])
+@validate_params(
+    JsonParam(
+        {
+            'namespace': [MinLength(1), MaxLength(255)],
+            'key': [MinLength(1), MaxLength(255)],
+            'value': [MaxLength(255)],
+        },
+        as_list=True,
+    )
+)
+def issue_82(valid: ValidRequest):
+    return flask.jsonify({'json': valid.get_json()})
+
+
 class TestNestedJson(TestCase):
     maxDiff = 2000
 
@@ -432,8 +447,11 @@ class TestNestedJson(TestCase):
                     'bands': [
                         {
                             'name': 'Metallica',
-                            'details': {'details': 'Los Angeles, California, U.S.',
-                                        'status': 'active'},
+                            'details': {
+                                'details': 'Los Angeles, California, U.S.',
+                                'description': 'very long description',
+                                'status': 'active',
+                            },
                             'persons': [
                                 {'name': 'James Hetfield'},
                                 {'name': 'Lars Ulrich'},
@@ -443,7 +461,11 @@ class TestNestedJson(TestCase):
                         },
                         {
                             'name': 'AC/DC',
-                            'details': {'details': 'Sydney, Australia', 'status': 'active'},
+                            'details': {
+                                'details': 'Sydney, Australia',
+                                'status': 'active',
+                                'description': 'positive',
+                            },
                             'persons': [
                                 {'name': 'Angus Young'},
                                 {'name': 'Stevie Young'},
@@ -459,17 +481,35 @@ class TestNestedJson(TestCase):
                 'json': {
                     'island': 'valid', 'iso': '2021-01-02', 'music': {
                         'bands': [
-                            {'details': {'details': 'Los Angeles, California, U.S.',
-                                         'status': 'active'},
-                             'name': 'Metallica',
-                             'persons': [{'name': 'James Hetfield'}, {'name': 'Lars Ulrich'},
-                                         {'name': 'Kirk Hammett'}, {'name': 'Robert Trujillo'}]},
-                            {'details': {'details': 'Sydney, Australia', 'status': 'active'},
-                             'name': 'AC/DC',
-                             'persons': [{'name': 'Angus Young'}, {'name': 'Stevie Young'},
-                                         {'name': 'Brian Johnson'}, {'name': 'Phil Rudd'},
-                                         {'name': 'Cliff Williams'}]
-                             }
+                            {
+                                'name': 'Metallica',
+                                'details': {
+                                    'details': 'Los Angeles, California, U.S.',
+                                    'description': 'very long description',
+                                    'status': 'active',
+                                },
+                                'persons': [
+                                    {'name': 'James Hetfield'},
+                                    {'name': 'Lars Ulrich'},
+                                    {'name': 'Kirk Hammett'},
+                                    {'name': 'Robert Trujillo'},
+                                ]
+                            },
+                            {
+                                'name': 'AC/DC',
+                                'details': {
+                                    'details': 'Sydney, Australia',
+                                    'status': 'active',
+                                    'description': 'positive',
+                                },
+                                'persons': [
+                                    {'name': 'Angus Young'},
+                                    {'name': 'Stevie Young'},
+                                    {'name': 'Brian Johnson'},
+                                    {'name': 'Phil Rudd'},
+                                    {'name': 'Cliff Williams'},
+                                ],
+                             },
                         ]
                     }
                 }
@@ -483,6 +523,67 @@ def test_json_route_with_error_formatter(self, data, expected, status):
             self.assertEqual(response.status, status)
             self.assertEqual(response.json, expected)
 
+    @parameterized.expand([
+        (
+            [{'key': 'testKey', 'value': 'testValue'}],
+            [{
+                'errors': [{'list_items': {'0': {'namespace': 'key is required'}}, 'path': 'root'}],
+                'message': 'invalid JSON parameters',
+            }],
+        ),
+        (
+            [{}, {'unknown_field': 'value'}],
+            [
+                {
+                    'errors': [
+                        {
+                            'list_items': {
+                                '0': {
+                                    'key': 'key is required',
+                                    'namespace': 'key is required',
+                                    'value': 'key is required',
+                                },
+                                '1': {
+                                    'key': 'key is required',
+                                    'namespace': 'key is required',
+                                    'value': 'key is required',
+                                },
+                            },
+                            'path': 'root',
+                        },
+                    ],
+                    'message': 'invalid JSON parameters',
+                },
+            ],
+        )
+    ])
+    def test_issue_82_negative(self, data, expected):
+        with _app2.test_client() as client:
+            response = client.post('/issue/82', data=json.dumps(data), content_type='application/json')
+            self.assertEqual(response.status, '400 BAD REQUEST')
+            self.assertEqual(response.json, expected)
+
+    def test_issue_82_positive(self):
+        with _app2.test_client() as client:
+            response = client.post(
+                '/issue/82',
+                data=json.dumps([
+                    dict(namespace='movies', key='science fiction', value='stranger things'),
+                    dict(namespace='music', key='downtempo,chill-out,dub,lounge', value='thievery corporation'),
+                ]),
+                content_type='application/json',
+            )
+
+            self.assertEqual(response.status, '200 OK')
+            self.assertEqual(
+                response.json,
+                dict(
+                    json=[
+                        dict(key='science fiction', namespace='movies', value='stranger things'),
+                        dict(key='downtempo,chill-out,dub,lounge', namespace='music', value='thievery corporation'),
+                    ]
+                ))
+
 
 class ExampleAfterParam(AbstractAfterParam):
     def validate(self, value: ValidRequest) -> Any: