# Buggy code
def _map(f, arr, na_mask=False, na_value=np.nan, dtype=object):
    if not len(arr):
        return np.ndarray(0, dtype=dtype)

    if isinstance(arr, ABCSeries):
        arr = arr.values
    if not isinstance(arr, np.ndarray):
        arr = np.asarray(arr, dtype=object)
    if na_mask:
        mask = isnull(arr)
        try:
            convert = not all(mask)
            result = lib.map_infer_mask(arr, f, mask.view(np.uint8), convert)
        except (TypeError, AttributeError):

            def g(x):
                try:
                    return f(x)
                except (TypeError, AttributeError):
                    return na_value

            return _map(g, arr, dtype=dtype)
        if na_value is not np.nan:
            np.putmask(result, mask, na_value)
            if result.dtype == object:
                result = lib.maybe_convert_objects(result)
        return result
    else:
        return lib.map_infer(arr, f)


# Traceback (TypeError)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-26-bc58c5c60bd2> in <module>()
----> 1 s.str.replace(r'[aeiou]', lambda m: m.group().upper())

/anaconda3/lib/python3.4/site-packages/pandas/core/strings.py in replace(self, pat, repl, n, case, flags)
1504     def replace(self, pat, repl, n=-1, case=True, flags=0):
1505         result = str_replace(self._data, pat, repl, n=n, case=case,
-> 1506                              flags=flags)
1507         return self._wrap_result(result)
1508

/anaconda3/lib/python3.4/site-packages/pandas/core/strings.py in str_replace(arr, pat, repl, n, case, flags)
320     # Check whether repl is valid (GH 13438)
321     if not is_string_like(repl):
--> 322         raise TypeError("repl must be a string")
323     use_re = not case or len(pat) > 1 or flags
324

TypeError: repl must be a string

# Fixed code
def _map(f, arr, na_mask=False, na_value=np.nan, dtype=object):
    if not len(arr):
        return np.ndarray(0, dtype=dtype)

    if isinstance(arr, ABCSeries):
        arr = arr.values
    if not isinstance(arr, np.ndarray):
        arr = np.asarray(arr, dtype=object)
    if na_mask:
        mask = isnull(arr)
        try:
            convert = not all(mask)
            result = lib.map_infer_mask(arr, f, mask.view(np.uint8), convert)
        except (TypeError, AttributeError) as e:
            # Reraise the exception if callable `f` got wrong number of args.
            # The user may want to be warned by this, instead of getting NaN
            if compat.PY2:
                p_err = r"takes (no|(exactly|at (least|most)) ?\d+) arguments?"
            else:
                p_err = (
                    r"((takes)|(missing)) (?(2)from \d+ to )?\d+ "
                    r"(?(3)required )positional arguments?"
                )

            if len(e.args) >= 1 and re.search(p_err, e.args[0]):
                raise e

            def g(x):
                try:
                    return f(x)
                except (TypeError, AttributeError):
                    return na_value

            return _map(g, arr, dtype=dtype)
        if na_value is not np.nan:
            np.putmask(result, mask, na_value)
            if result.dtype == object:
                result = lib.maybe_convert_objects(result)
        return result
    else:
        return lib.map_infer(arr, f)