# Buggy code
def _ConvertDictToObject(cls, json_dict):
    """Converts a JSON dict into an object.

    The dictionary of the JSON serialized objects consists of:
    {
        '__type__': 'AttributeContainer'
        '__container_type__': ...
        ...
    }

    Here '__type__' indicates the object base type. In this case
    'AttributeContainer'.

    '__container_type__' indicates the attribute container type.

    The rest of the elements of the dictionary make up the attributes.

    Args:
      json_dict (dict[str, object]): JSON serialized objects.

    Returns:
      A deserialized object which can be:
        * an attribute container (instance of AttributeContainer);
        * a dictionary;
        * a list;
        * a tuple.

    Raises:
      ValueError: if the class type or container type is not supported.
    """
    # Use __type__ to indicate the object class type.
    class_type = json_dict.get("__type__", None)
    if not class_type:
        # Dealing with a regular dict.
        return json_dict

    if class_type == "bytes":
        return binascii.a2b_qp(json_dict["stream"])

    elif class_type == "tuple":
        return tuple(cls._ConvertListToObject(json_dict["values"]))

    elif class_type == "collections.Counter":
        return cls._ConvertDictToCollectionsCounter(json_dict)

    elif class_type == "AttributeContainer":
        # Use __container_type__ to indicate the attribute container type.
        container_type = json_dict.get("__container_type__", None)

    # Since we would like the JSON as flat as possible we handle decoding
    # a path specification.
    elif class_type == "PathSpec":
        return cls._ConvertDictToPathSpec(json_dict)

    else:
        raise ValueError("Unsupported class type: {0:s}".format(class_type))

    container_class = (
        containers_manager.AttributeContainersManager.GetAttributeContainer(
            container_type
        )
    )
    if not container_class:
        raise ValueError("Unsupported container type: {0:s}".format(container_type))

    container_object = container_class()
    for attribute_name, attribute_value in iter(json_dict.items()):
        if attribute_name.startswith("__"):
            continue

        # Be strict about which attributes to set in non event objects.
        if (
            container_type != "event"
            and attribute_name not in container_object.__dict__
        ):
            continue

        # Note that "_tags" is the name for "labels" in EventTag prior to
        # version 1.4.1-20160131
        if container_type == "event_tag" and attribute_name == "_event_tags":
            attribute_name = "labels"

        if isinstance(attribute_value, dict):
            attribute_value = cls._ConvertDictToObject(attribute_value)

        elif isinstance(attribute_value, list):
            attribute_value = cls._ConvertListToObject(attribute_value)

        setattr(container_object, attribute_name, attribute_value)

    return container_object


# Traceback (KeyError)
[ERROR] (nsrlsvr   ) PID:XXXXX <analysis_process> <dfvfs.path.os_path_spec.OSPathSpec object at 0xXXXXXXXXXXXX>
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/plaso/multi_processing/analysis_process.py", line 138, in _Main
self._analysis_mediator.ProduceAnalysisReport(self._analysis_plugin)
File "/usr/lib/python2.7/dist-packages/plaso/analysis/mediator.py", line 95, in ProduceAnalysisReport
analysis_report = plugin.CompileReport(self)
File "/usr/lib/python2.7/dist-packages/plaso/analysis/interface.py", line 280, in CompileReport
hash_analysis)
File "/usr/lib/python2.7/dist-packages/plaso/analysis/interface.py", line 187, in _HandleHashAnalysis
event_uuids = self._event_uuids_by_pathspec.pop(pathspec)
KeyError: <dfvfs.path.os_path_spec.OSPathSpec object at 0xXXXXXXXXXXXX>

# Fixed code
def _ConvertDictToObject(cls, json_dict):
    """Converts a JSON dict into an object.

    The dictionary of the JSON serialized objects consists of:
    {
        '__type__': 'AttributeContainer'
        '__container_type__': ...
        ...
    }

    Here '__type__' indicates the object base type. In this case
    'AttributeContainer'.

    '__container_type__' indicates the attribute container type.

    The rest of the elements of the dictionary make up the attributes.

    Args:
      json_dict (dict[str, object]): JSON serialized objects.

    Returns:
      A deserialized object which can be:
        * an attribute container (instance of AttributeContainer);
        * a dictionary;
        * a list;
        * a tuple.

    Raises:
      ValueError: if the class type or container type is not supported.
    """
    # Use __type__ to indicate the object class type.
    class_type = json_dict.get("__type__", None)
    if not class_type:
        # Dealing with a regular dict.
        return json_dict

    if class_type == "bytes":
        return binascii.a2b_qp(json_dict["stream"])

    elif class_type == "tuple":
        return tuple(cls._ConvertListToObject(json_dict["values"]))

    elif class_type == "collections.Counter":
        return cls._ConvertDictToCollectionsCounter(json_dict)

    elif class_type == "AttributeContainer":
        # Use __container_type__ to indicate the attribute container type.
        container_type = json_dict.get("__container_type__", None)

    # Since we would like the JSON as flat as possible we handle decoding
    # a path specification.
    elif class_type == "PathSpec":
        return cls._ConvertDictToPathSpec(json_dict)

    else:
        raise ValueError("Unsupported class type: {0:s}".format(class_type))

    container_class = (
        containers_manager.AttributeContainersManager.GetAttributeContainer(
            container_type
        )
    )
    if not container_class:
        raise ValueError("Unsupported container type: {0:s}".format(container_type))

    container_object = container_class()
    for attribute_name, attribute_value in iter(json_dict.items()):
        if attribute_name.startswith("__"):
            continue

        # Event tags should be serialized separately.
        # TODO: remove when analysis report no longer defines event tags.
        if container_type == "analysis_report" and attribute_name == "_event_tags":
            continue

        # Be strict about which attributes to set in non event objects.
        if (
            container_type != "event"
            and attribute_name not in container_object.__dict__
        ):
            continue

        if isinstance(attribute_value, dict):
            attribute_value = cls._ConvertDictToObject(attribute_value)

        elif isinstance(attribute_value, list):
            attribute_value = cls._ConvertListToObject(attribute_value)

        setattr(container_object, attribute_name, attribute_value)

    return container_object