# Buggy code
def decode_list(
    data,
    encoding=None,
    errors="strict",
    keep=False,
    normalize=False,
    preserve_dict_class=False,
    preserve_tuples=False,
):
    """
    Decode all string values to Unicode
    """
    rv = []
    for item in data:
        if isinstance(item, list):
            item = decode_list(
                item,
                encoding,
                errors,
                keep,
                normalize,
                preserve_dict_class,
                preserve_tuples,
            )
        elif isinstance(item, tuple):
            item = (
                decode_tuple(
                    item, encoding, errors, keep, normalize, preserve_dict_class
                )
                if preserve_tuples
                else decode_list(
                    item,
                    encoding,
                    errors,
                    keep,
                    normalize,
                    preserve_dict_class,
                    preserve_tuples,
                )
            )
        elif isinstance(item, collections.Mapping):
            item = decode_dict(
                item,
                encoding,
                errors,
                keep,
                normalize,
                preserve_dict_class,
                preserve_tuples,
            )
        else:
            try:
                item = salt.utils.stringutils.to_unicode(
                    item, encoding, errors, normalize
                )
            except TypeError:
                # to_unicode raises a TypeError when input is not a
                # string/bytestring/bytearray. This is expected and simply
                # means we are going to leave the value as-is.
                pass
            except UnicodeDecodeError:
                if not keep:
                    raise

        rv.append(item)
    return rv


# Traceback (TypeError)
2018-04-04 05:37:16,969 [salt.loaded.int.pillar.pillar_ldap:262 ][CRITICAL][5777] Failed to retrieve pillar data from LDAP:
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/salt/pillar/pillar_ldap.py", line 256, in _do_search
**connargs)['results']
File "/usr/lib/python2.7/site-packages/salt/modules/ldapmod.py", line 150, in search
results = _ldap.search_s(dn, int(scope), filter, attrs)
File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 552, in search_s
return self.search_ext_s(base,scope,filterstr,attrlist,attrsonly,None,None,timeout=self.timeout)
File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 545, in search_ext_s
msgid = self.search_ext(base,scope,filterstr,attrlist,attrsonly,serverctrls,clientctrls,timeout,sizelimit)
File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 541, in search_ext
timeout,sizelimit,
File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 99, in _ldap_call
result = func(*args,**kwargs)
TypeError: ('expected string in list', u'uid')

# Fixed code
def decode_list(
    data,
    encoding=None,
    errors="strict",
    keep=False,
    normalize=False,
    preserve_dict_class=False,
    preserve_tuples=False,
    to_str=False,
):
    """
    Decode all string values to Unicode. Optionally use to_str=True to ensure
    strings are str types and not unicode on Python 2.
    """
    _decode_func = (
        salt.utils.stringutils.to_unicode
        if not to_str
        else salt.utils.stringutils.to_str
    )
    rv = []
    for item in data:
        if isinstance(item, list):
            item = decode_list(
                item,
                encoding,
                errors,
                keep,
                normalize,
                preserve_dict_class,
                preserve_tuples,
                to_str,
            )
        elif isinstance(item, tuple):
            item = (
                decode_tuple(
                    item, encoding, errors, keep, normalize, preserve_dict_class, to_str
                )
                if preserve_tuples
                else decode_list(
                    item,
                    encoding,
                    errors,
                    keep,
                    normalize,
                    preserve_dict_class,
                    preserve_tuples,
                    to_str,
                )
            )
        elif isinstance(item, collections.Mapping):
            item = decode_dict(
                item,
                encoding,
                errors,
                keep,
                normalize,
                preserve_dict_class,
                preserve_tuples,
                to_str,
            )
        else:
            try:
                item = _decode_func(item, encoding, errors, normalize)
            except TypeError:
                # to_unicode raises a TypeError when input is not a
                # string/bytestring/bytearray. This is expected and simply
                # means we are going to leave the value as-is.
                pass
            except UnicodeDecodeError:
                if not keep:
                    raise

        rv.append(item)
    return rv