diff --git a/lib/ansible/errors/__init__.py b/lib/ansible/errors/__init__.py
index 3bfed1dbbf8..80cba82be97 100644
--- a/lib/ansible/errors/__init__.py
+++ b/lib/ansible/errors/__init__.py
@@ -204,3 +204,10 @@ class AnsibleUndefinedVariable(AnsibleRuntimeError):
 class AnsibleFileNotFound(AnsibleRuntimeError):
     ''' a file missing failure '''
     pass
+
+class AnsibleActionSkip(AnsibleRuntimeError):
+    ''' an action runtime skip'''
+    pass
+class AnsibleActionFail(AnsibleRuntimeError):
+    ''' an action runtime failure'''
+    pass
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
index 847c451fb77..ab9938a6155 100644
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -25,7 +25,7 @@ import time
 import traceback
 
 from ansible import constants as C
-from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleConnectionFailure
+from ansible.errors import AnsibleError, AnsibleParserError, AnsibleUndefinedVariable, AnsibleConnectionFailure, AnsibleActionFail, AnsibleActionSkip
 from ansible.executor.task_result import TaskResult
 from ansible.module_utils.six import iteritems, string_types, binary_type
 from ansible.module_utils._text import to_text
@@ -526,6 +526,10 @@ class TaskExecutor:
             display.debug("running the handler")
             try:
                 result = self._handler.run(task_vars=variables)
+            except AnsibleActionSkip as e:
+                return dict(skipped=True, msg=to_text(e))
+            except AnsibleActionFail as e:
+                return dict(failed=True, msg=to_text(e))
             except AnsibleConnectionFailure as e:
                 return dict(unreachable=True, msg=to_text(e))
             display.debug("handler run complete")
diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py
index c56db2ff31c..37f423dc878 100644
--- a/lib/ansible/plugins/action/__init__.py
+++ b/lib/ansible/plugins/action/__init__.py
@@ -30,7 +30,7 @@ import time
 from abc import ABCMeta, abstractmethod
 
 from ansible import constants as C
-from ansible.errors import AnsibleError, AnsibleConnectionFailure
+from ansible.errors import AnsibleError, AnsibleConnectionFailure, AnsibleActionSkip, AnsibleActionFail
 from ansible.executor.module_common import modify_module, build_windows_module_payload
 from ansible.module_utils.json_utils import _filter_non_json_lines
 from ansible.module_utils.six import binary_type, string_types, text_type, iteritems, with_metaclass
@@ -93,14 +93,11 @@ class ActionBase(with_metaclass(ABCMeta, object)):
         result = {}
 
         if self._task.async and not self._supports_async:
-            result['msg'] = 'async is not supported for this task.'
-            result['failed'] = True
+            raise AnsibleActionFail('async is not supported for this task.')
         elif self._play_context.check_mode and not self._supports_check_mode:
-            result['msg'] = 'check mode is not supported for this task.'
-            result['skipped'] = True
+            raise AnsibleActionSkip('check mode is not supported for this task.')
         elif self._task.async and self._play_context.check_mode:
-            result['msg'] = 'check mode and async cannot be used on same task.'
-            result['failed'] = True
+            raise AnsibleActionFail('check mode and async cannot be used on same task.')
 
         return result
 
diff --git a/lib/ansible/plugins/action/add_host.py b/lib/ansible/plugins/action/add_host.py
index bc2d94f9f56..acab50334ca 100644
--- a/lib/ansible/plugins/action/add_host.py
+++ b/lib/ansible/plugins/action/add_host.py
@@ -45,9 +45,6 @@ class ActionModule(ActionBase):
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        if result.get('skipped', False) or result.get('failed', False):
-            return result
-
         # Parse out any hostname:port patterns
         new_name = self._task.args.get('name', self._task.args.get('hostname', None))
         display.vv("creating host via 'add_host': hostname=%s" % new_name)
diff --git a/lib/ansible/plugins/action/assemble.py b/lib/ansible/plugins/action/assemble.py
index 70211d62032..2da6527c4cf 100644
--- a/lib/ansible/plugins/action/assemble.py
+++ b/lib/ansible/plugins/action/assemble.py
@@ -84,9 +84,6 @@ class ActionModule(ActionBase):
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        if result.get('skipped', False) or result.get('failed', False):
-            return result
-
         if task_vars is None:
             task_vars = dict()
 
diff --git a/lib/ansible/plugins/action/copy.py b/lib/ansible/plugins/action/copy.py
index 4be4b36e53c..7654989376e 100644
--- a/lib/ansible/plugins/action/copy.py
+++ b/lib/ansible/plugins/action/copy.py
@@ -40,9 +40,6 @@ class ActionModule(ActionBase):
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        if result.get('skipped', False) or result.get('failed', False):
-            return result
-
         source  = self._task.args.get('src', None)
         content = self._task.args.get('content', None)
         dest    = self._task.args.get('dest', None)
diff --git a/lib/ansible/plugins/action/package.py b/lib/ansible/plugins/action/package.py
index cd6d3851f03..f45a81640bd 100644
--- a/lib/ansible/plugins/action/package.py
+++ b/lib/ansible/plugins/action/package.py
@@ -38,9 +38,6 @@ class ActionModule(ActionBase):
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        if result.get('skipped', False) or result.get('failed', False):
-            return result
-
         module = self._task.args.get('use', 'auto')
 
         if module == 'auto':
diff --git a/lib/ansible/plugins/action/script.py b/lib/ansible/plugins/action/script.py
index 6195917fa78..2111246acaf 100644
--- a/lib/ansible/plugins/action/script.py
+++ b/lib/ansible/plugins/action/script.py
@@ -34,9 +34,6 @@ class ActionModule(ActionBase):
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        if result.get('skipped', False) or result.get('failed', False):
-            return result
-
         if not tmp:
             tmp = self._make_tmp_path()
 
diff --git a/lib/ansible/plugins/action/service.py b/lib/ansible/plugins/action/service.py
index 07e9dde81b0..91ab0e6bd3a 100644
--- a/lib/ansible/plugins/action/service.py
+++ b/lib/ansible/plugins/action/service.py
@@ -37,9 +37,6 @@ class ActionModule(ActionBase):
 
         result = super(ActionModule, self).run(tmp, task_vars)
 
-        if result.get('skipped', False) or result.get('failed', False):
-            return result
-
         module = self._task.args.get('use', 'auto').lower()
 
         if module == 'auto':
diff --git a/test/integration/targets/module_utils/module_utils_test.yml b/test/integration/targets/module_utils/module_utils_test.yml
index a1317270840..ee737c6cdce 100644
--- a/test/integration/targets/module_utils/module_utils_test.yml
+++ b/test/integration/targets/module_utils/module_utils_test.yml
@@ -36,7 +36,7 @@
   - name: Make sure the we used the local facts.py, not the one shipped with ansible
     assert:
       that:
-        - 'result["data"] == "overridden facts.py"'
+        - result["data"] == "overridden facts.py"
 
   - name: Test that importing a module that only exists inside of a submodule does not work
     test_failure:
@@ -47,5 +47,5 @@
   - name: Make sure we failed in AnsiBallZ
     assert:
       that:
-        - 'result["failed"] == True'
-        - '"Could not find imported module support code for test_failure.  Looked for either foo.py or zebra.py" == result["msg"]'
+        - result|failed
+        - result['msg'] == "Could not find imported module support code for test_failure.  Looked for either foo.py or zebra.py"
diff --git a/test/integration/targets/script/tasks/main.yml b/test/integration/targets/script/tasks/main.yml
index 6650ede6f00..7b314441901 100644
--- a/test/integration/targets/script/tasks/main.yml
+++ b/test/integration/targets/script/tasks/main.yml
@@ -81,5 +81,5 @@
 - name: assert task with async param failed
   assert:
     that:
-      - 'script_result3.failed'
-      - 'script_result3.msg == "async is not supported for this task."'
+      - script_result3|failed
+      - script_result3.msg == "async is not supported for this task."
diff --git a/test/units/plugins/action/test_raw.py b/test/units/plugins/action/test_raw.py
index c48d38b4379..b6e12ee339d 100644
--- a/test/units/plugins/action/test_raw.py
+++ b/test/units/plugins/action/test_raw.py
@@ -18,7 +18,7 @@
 from __future__ import (absolute_import, division, print_function)
 __metaclass__ = type
 
-
+from ansible.errors import AnsibleActionFail
 from ansible.compat.tests import unittest
 from ansible.compat.tests.mock import patch, MagicMock, Mock
 from ansible.plugins.action.raw import ActionModule
@@ -43,7 +43,7 @@ class TestCopyResultExclude(unittest.TestCase):
 
         play_context = Mock()
         task = MagicMock(Task)
-        task.async = MagicMock()
+        task.async = False
         connection = Mock()
 
         task.args = {'_raw_params': 'Args1'}
@@ -60,25 +60,22 @@ class TestCopyResultExclude(unittest.TestCase):
 
         play_context = Mock()
         task = MagicMock(Task)
-        task.async = MagicMock()
+        task.async = False
         connection = Mock()
 
         task.args = {'_raw_params': 'Args1'}
         play_context.check_mode = True
 
-        self.mock_am = ActionModule(task, connection, play_context, loader=None, templar=None, shared_loader_obj=None)
-        self.mock_am._low_level_execute_command = Mock(return_value = {})
-        self.mock_am.display = Mock()
-
-        skipped_result = self.mock_am.run()
-
-        self.assertEqual(skipped_result.get('skipped'), True)
+        try:
+            self.mock_am = ActionModule(task, connection, play_context, loader=None, templar=None, shared_loader_obj=None)
+        except AnsibleActionFail:
+            pass
 
     def test_raw_test_environment_is_None(self):
 
         play_context = Mock()
         task = MagicMock(Task)
-        task.async = MagicMock()
+        task.async = False
         connection = Mock()
 
         task.args = {'_raw_params': 'Args1'}
@@ -95,7 +92,7 @@ class TestCopyResultExclude(unittest.TestCase):
 
         play_context = Mock()
         task = MagicMock(Task)
-        task.async = MagicMock()
+        task.async = False
         connection = Mock()
 
         task.args = {'_raw_params': 'Args1'}