# Buggy code
def dumps(self, msg, use_bin_type=False):
    """
    Run the correct dumps serialization format

    :param use_bin_type: Useful for Python 3 support. Tells msgpack to
                         differentiate between 'str' and 'bytes' types
                         by encoding them differently.
                         Since this changes the wire protocol, this
                         option should not be used outside of IPC.
    """
    try:
        if msgpack.version >= (0, 4, 0):
            # msgpack only supports 'use_bin_type' starting in 0.4.0.
            # Due to this, if we don't need it, don't pass it at all so
            # that under Python 2 we can still work with older versions
            # of msgpack.
            return msgpack.dumps(msg, use_bin_type=use_bin_type)
        else:
            return msgpack.dumps(msg)
    except (OverflowError, msgpack.exceptions.PackValueError):
        # msgpack can't handle the very long Python longs for jids
        # Convert any very long longs to strings
        # We borrow the technique used by TypeError below
        def verylong_encoder(obj):
            if isinstance(obj, dict):
                for key, value in six.iteritems(obj.copy()):
                    obj[key] = verylong_encoder(value)
                return dict(obj)
            elif isinstance(obj, (list, tuple)):
                obj = list(obj)
                for idx, entry in enumerate(obj):
                    obj[idx] = verylong_encoder(entry)
                return obj
            # This is a spurious lint failure as we are gating this check
            # behind a check for six.PY2.
            if six.PY2 and isinstance(obj, long) and long > pow(2, 64):  # pylint: disable=incompatible-py3-code
                return six.text_type(obj)
            elif six.PY3 and isinstance(obj, int) and int > pow(2, 64):
                return six.text_type(obj)
            else:
                return obj

        if msgpack.version >= (0, 4, 0):
            return msgpack.dumps(verylong_encoder(msg), use_bin_type=use_bin_type)
        else:
            return msgpack.dumps(verylong_encoder(msg))
    except TypeError as e:
        # msgpack doesn't support datetime.datetime datatype
        # So here we have converted datetime.datetime to custom datatype
        # This is msgpack Extended types numbered 78
        def default(obj):
            return msgpack.ExtType(78, obj)

        def dt_encode(obj):
            datetime_str = obj.strftime("%Y%m%dT%H:%M:%S.%f")
            if msgpack.version >= (0, 4, 0):
                return msgpack.packb(
                    datetime_str, default=default, use_bin_type=use_bin_type
                )
            else:
                return msgpack.packb(datetime_str, default=default)

        def datetime_encoder(obj):
            if isinstance(obj, dict):
                for key, value in six.iteritems(obj.copy()):
                    encodedkey = datetime_encoder(key)
                    if key != encodedkey:
                        del obj[key]
                        key = encodedkey
                    obj[key] = datetime_encoder(value)
                return dict(obj)
            elif isinstance(obj, (list, tuple)):
                obj = list(obj)
                for idx, entry in enumerate(obj):
                    obj[idx] = datetime_encoder(entry)
                return obj
            if isinstance(obj, datetime.datetime):
                return dt_encode(obj)
            else:
                return obj

        def immutable_encoder(obj):
            log.debug("IMMUTABLE OBJ: %s", obj)
            if isinstance(obj, immutabletypes.ImmutableDict):
                return dict(obj)
            if isinstance(obj, immutabletypes.ImmutableList):
                return list(obj)
            if isinstance(obj, immutabletypes.ImmutableSet):
                return set(obj)

        if "datetime.datetime" in six.text_type(e):
            if msgpack.version >= (0, 4, 0):
                return msgpack.dumps(datetime_encoder(msg), use_bin_type=use_bin_type)
            else:
                return msgpack.dumps(datetime_encoder(msg))
        elif "Immutable" in six.text_type(e):
            if msgpack.version >= (0, 4, 0):
                return msgpack.dumps(
                    msg, default=immutable_encoder, use_bin_type=use_bin_type
                )
            else:
                return msgpack.dumps(msg, default=immutable_encoder)

        if msgpack.version >= (0, 2, 0):
            # Should support OrderedDict serialization, so, let's
            # raise the exception
            raise

        # msgpack is < 0.2.0, let's make its life easier
        # Since OrderedDict is identified as a dictionary, we can't
        # make use of msgpack custom types, we will need to convert by
        # hand.
        # This means iterating through all elements of a dictionary or
        # list/tuple
        def odict_encoder(obj):
            if isinstance(obj, dict):
                for key, value in six.iteritems(obj.copy()):
                    obj[key] = odict_encoder(value)
                return dict(obj)
            elif isinstance(obj, (list, tuple)):
                obj = list(obj)
                for idx, entry in enumerate(obj):
                    obj[idx] = odict_encoder(entry)
                return obj
            return obj

        if msgpack.version >= (0, 4, 0):
            return msgpack.dumps(odict_encoder(msg), use_bin_type=use_bin_type)
        else:
            return msgpack.dumps(odict_encoder(msg))
    except (SystemError, TypeError) as exc:  # pylint: disable=W0705
        log.critical(
            "Unable to serialize message! Consider upgrading msgpack. "
            "Message which failed was %s, with exception %s",
            msg,
            exc,
        )


# Traceback (SaltClientError)
2018-02-26 18:02:15,266 [salt.minion      :204 ][WARNING ][16492] Master ip address changed from 10.1.51.25 to 10.1.51.24
2018-02-26 18:02:15,616 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:16,613 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:17,611 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:18,611 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:19,611 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:20,288 [salt.minion      :204 ][WARNING ][16492] Master ip address changed from 10.1.51.24 to 10.1.51.25
2018-02-26 18:02:20,611 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:21,611 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:22,610 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:23,619 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:24,620 [salt.minion      :433 ][ERROR   ][16492] Exception unsupported operand type(s) for -: 'str' and 'datetime.datetime' occurred in scheduled job
2018-02-26 18:02:25,300 [salt.minion      :644 ][ERROR   ][16492] No master could be reached or all masters denied the minion's connection attempt.
2018-02-26 18:02:25,301 [salt.scripts     :146 ][WARNING ][16492] Fatal functionality error caught by minion handler:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/salt/scripts.py", line 144, in minion_process
minion.start()
File "/usr/lib/python2.7/site-packages/salt/cli/daemons.py", line 350, in start
raise SaltClientError('Minion could not connect to Master')
SaltClientError: Minion could not connect to Master
2018-02-26 18:02:25,301 [salt.scripts     :147 ][WARNING ][16492] ** Restarting minion **

# Fixed code
def dumps(self, msg, use_bin_type=False):
    """
    Run the correct dumps serialization format

    :param use_bin_type: Useful for Python 3 support. Tells msgpack to
                         differentiate between 'str' and 'bytes' types
                         by encoding them differently.
                         Since this changes the wire protocol, this
                         option should not be used outside of IPC.
    """

    def ext_type_encoder(obj):
        if isinstance(obj, six.integer_types):
            # msgpack can't handle the very long Python longs for jids
            # Convert any very long longs to strings
            return six.text_type(obj)
        elif isinstance(obj, datetime.datetime):
            # msgpack doesn't support datetime.datetime datatype
            # So here we have converted datetime.datetime to custom datatype
            # This is msgpack Extended types numbered 78
            return msgpack.ExtType(
                78, salt.utils.stringutils.to_bytes(obj.strftime("%Y%m%dT%H:%M:%S.%f"))
            )
        # The same for immutable types
        elif isinstance(obj, immutabletypes.ImmutableDict):
            return dict(obj)
        elif isinstance(obj, immutabletypes.ImmutableList):
            return list(obj)
        elif isinstance(obj, (set, immutabletypes.ImmutableSet)):
            # msgpack can't handle set so translate it to tuple
            return tuple(obj)
        # Nothing known exceptions found. Let msgpack raise it's own.
        return obj

    try:
        if msgpack.version >= (0, 4, 0):
            # msgpack only supports 'use_bin_type' starting in 0.4.0.
            # Due to this, if we don't need it, don't pass it at all so
            # that under Python 2 we can still work with older versions
            # of msgpack.
            return msgpack.dumps(
                msg, default=ext_type_encoder, use_bin_type=use_bin_type
            )
        else:
            return msgpack.dumps(msg, default=ext_type_encoder)
    except (OverflowError, msgpack.exceptions.PackValueError):
        # msgpack<=0.4.6 don't call ext encoder on very long integers raising the error instead.
        # Convert any very long longs to strings and call dumps again.
        def verylong_encoder(obj):
            if isinstance(obj, dict):
                for key, value in six.iteritems(obj.copy()):
                    obj[key] = verylong_encoder(value)
                return dict(obj)
            elif isinstance(obj, (list, tuple)):
                obj = list(obj)
                for idx, entry in enumerate(obj):
                    obj[idx] = verylong_encoder(entry)
                return obj
            # A value of an Integer object is limited from -(2^63) upto (2^64)-1 by MessagePack
            # spec. Here we care only of JIDs that are positive integers.
            if isinstance(obj, six.integer_types) and obj >= pow(2, 64):
                return six.text_type(obj)
            else:
                return obj

        msg = verylong_encoder(msg)
        if msgpack.version >= (0, 4, 0):
            return msgpack.dumps(
                msg, default=ext_type_encoder, use_bin_type=use_bin_type
            )
        else:
            return msgpack.dumps(msg, default=ext_type_encoder)