# Buggy code
def _do_handler_run(
    self, handler, handler_name, iterator, play_context, notified_hosts=None
):
    # FIXME: need to use iterator.get_failed_hosts() instead?
    # if not len(self.get_hosts_remaining(iterator._play)):
    #    self._tqm.send_callback('v2_playbook_on_no_hosts_remaining')
    #    result = False
    #    break
    saved_name = handler.name
    handler.name = handler_name
    self._tqm.send_callback("v2_playbook_on_handler_task_start", handler)
    handler.name = saved_name

    if notified_hosts is None:
        notified_hosts = self._notified_handlers[handler._uuid]

    run_once = False
    try:
        action = action_loader.get(handler.action, class_only=True)
        if handler.run_once or getattr(action, "BYPASS_HOST_LOOP", False):
            run_once = True
    except KeyError:
        # we don't care here, because the action may simply not have a
        # corresponding action plugin
        pass

    host_results = []
    for host in notified_hosts:
        if not handler.has_triggered(host) and (
            not iterator.is_failed(host) or play_context.force_handlers
        ):
            task_vars = self._variable_manager.get_vars(
                loader=self._loader, play=iterator._play, host=host, task=handler
            )
            self.add_tqm_variables(task_vars, play=iterator._play)
            self._queue_task(host, handler, task_vars, play_context)
            if run_once:
                break

    # collect the results from the handler run
    host_results = self._wait_on_pending_results(iterator)

    try:
        included_files = IncludedFile.process_include_results(
            host_results,
            self._tqm,
            iterator=iterator,
            inventory=self._inventory,
            loader=self._loader,
            variable_manager=self._variable_manager,
        )
    except AnsibleError as e:
        return False

    result = True
    if len(included_files) > 0:
        for included_file in included_files:
            try:
                new_blocks = self._load_included_file(
                    included_file, iterator=iterator, is_handler=True
                )
                # for every task in each block brought in by the include, add the list
                # of hosts which included the file to the notified_handlers dict
                for block in new_blocks:
                    iterator._play.handlers.append(block)
                    iterator.cache_block_tasks(block)
                    for task in block.block:
                        result = self._do_handler_run(
                            handler=task,
                            handler_name=None,
                            iterator=iterator,
                            play_context=play_context,
                            notified_hosts=included_file._hosts[:],
                        )
                        if not result:
                            break
            except AnsibleError as e:
                for host in included_file._hosts:
                    iterator.mark_host_failed(host)
                    self._tqm._failed_hosts[host.name] = True
                display.warning(str(e))
                continue

    # wipe the notification list
    self._notified_handlers[handler._uuid] = []
    display.debug("done running handlers, result is: %s" % result)
    return result


# Traceback (KeyError)
ansible-playbook -vvvv playbook.yml
No config file found; using defaults
[WARNING]: Host file not found: /etc/ansible/hosts

[WARNING]: provided hosts list is empty, only localhost is available

Loading callback plugin default of type stdout, v2.0 from /usr/local/lib/python2.7/site-packages/ansible/plugins/callback/__init__.pyc

PLAYBOOK: playbook.yml *********************************************************
1 plays in playbook.yml

PLAY [localhost] ***************************************************************

TASK [include_role] ************************************************************
task path: /Users/xxx/workspace/xxx/playbook.yml:6

TASK [handlertest : command] ***************************************************
task path: /Users/xxx/workspace/xxx/roles/handlertest/tasks/main.yml:3
Using module file /usr/local/lib/python2.7/site-packages/ansible/modules/core/commands/command.py
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: xxx
<127.0.0.1> EXEC /bin/sh -c '( umask 77 &amp;&amp; mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975 `" &amp;&amp; echo ansible-tmp-1478572148.78-187995060050975="` echo $HOME/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975 `" ) &amp;&amp; sleep 0'
<127.0.0.1> PUT /var/folders/62/pqgvprd11fb4k6shw2pdzkqm0000gq/T/tmpGA2Gau TO /Users/xxx/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975/command.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /Users/xxx/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975/ /Users/xxx/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975/command.py &amp;&amp; sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/local/opt/python/bin/python2.7 /Users/xxx/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975/command.py; rm -rf "/Users/xxx/.ansible/tmp/ansible-tmp-1478572148.78-187995060050975/" > /dev/null 2>&amp;1 &amp;&amp; sleep 0'
ERROR! Unexpected Exception: HANDLER: handlertest : Some handler
the full traceback was:

Traceback (most recent call last):
File "/usr/local/bin/ansible-playbook", line 103, in <module>
exit_code = cli.run()
File "/usr/local/lib/python2.7/site-packages/ansible/cli/playbook.py", line 159, in run
results = pbex.run()
File "/usr/local/lib/python2.7/site-packages/ansible/executor/playbook_executor.py", line 154, in run
result = self._tqm.run(play=play)
File "/usr/local/lib/python2.7/site-packages/ansible/executor/task_queue_manager.py", line 282, in run
play_return = strategy.run(iterator, play_context)
File "/usr/local/lib/python2.7/site-packages/ansible/plugins/strategy/linear.py", line 278, in run
results += self._wait_on_pending_results(iterator)
File "/usr/local/lib/python2.7/site-packages/ansible/plugins/strategy/__init__.py", line 534, in _wait_on_pending_results
results = self._process_pending_results(iterator)
File "/usr/local/lib/python2.7/site-packages/ansible/plugins/strategy/__init__.py", line 399, in _process_pending_results
if original_host not in self._notified_handlers[target_handler]:
KeyError: HANDLER: handlertest : Some handler

# Fixed code
def _do_handler_run(
    self, handler, handler_name, iterator, play_context, notified_hosts=None
):
    # FIXME: need to use iterator.get_failed_hosts() instead?
    # if not len(self.get_hosts_remaining(iterator._play)):
    #    self._tqm.send_callback('v2_playbook_on_no_hosts_remaining')
    #    result = False
    #    break
    saved_name = handler.name
    handler.name = handler_name
    self._tqm.send_callback("v2_playbook_on_handler_task_start", handler)
    handler.name = saved_name

    if notified_hosts is None:
        notified_hosts = self._notified_handlers[handler._uuid]

    run_once = False
    try:
        action = action_loader.get(handler.action, class_only=True)
        if handler.run_once or getattr(action, "BYPASS_HOST_LOOP", False):
            run_once = True
    except KeyError:
        # we don't care here, because the action may simply not have a
        # corresponding action plugin
        pass

    host_results = []
    for host in notified_hosts:
        if not handler.has_triggered(host) and (
            not iterator.is_failed(host) or play_context.force_handlers
        ):
            if handler._uuid not in iterator._task_uuid_cache:
                iterator._task_uuid_cache[handler._uuid] = handler
            task_vars = self._variable_manager.get_vars(
                loader=self._loader, play=iterator._play, host=host, task=handler
            )
            self.add_tqm_variables(task_vars, play=iterator._play)
            self._queue_task(host, handler, task_vars, play_context)
            if run_once:
                break

    # collect the results from the handler run
    host_results = self._wait_on_pending_results(iterator)

    try:
        included_files = IncludedFile.process_include_results(
            host_results,
            self._tqm,
            iterator=iterator,
            inventory=self._inventory,
            loader=self._loader,
            variable_manager=self._variable_manager,
        )
    except AnsibleError as e:
        return False

    result = True
    if len(included_files) > 0:
        for included_file in included_files:
            try:
                new_blocks = self._load_included_file(
                    included_file, iterator=iterator, is_handler=True
                )
                # for every task in each block brought in by the include, add the list
                # of hosts which included the file to the notified_handlers dict
                for block in new_blocks:
                    iterator._play.handlers.append(block)
                    iterator.cache_block_tasks(block)
                    for task in block.block:
                        result = self._do_handler_run(
                            handler=task,
                            handler_name=None,
                            iterator=iterator,
                            play_context=play_context,
                            notified_hosts=included_file._hosts[:],
                        )
                        if not result:
                            break
            except AnsibleError as e:
                for host in included_file._hosts:
                    iterator.mark_host_failed(host)
                    self._tqm._failed_hosts[host.name] = True
                display.warning(str(e))
                continue

    # wipe the notification list
    self._notified_handlers[handler._uuid] = []
    display.debug("done running handlers, result is: %s" % result)
    return result