Q:

Recursion: design a recursive function called replicate_recur which will receive two arguments:

The below code is a recursive function which takes two arguments and return something  like [5,5,5].
def recursive(times, data):  
    if not isinstance(times,int):  
         raise ValueError("times must be an int")  
    if not (isinstance(data,int) or isinstance(data, str)):  
        raise ValueError("data must be an int or a string")  
    if times <= 0:  
        return []  
    return [data] + recursive(times, data - 1)  

print(recursive(3, 5))

Why is the code throwing a recursive error?

A:

Let's try to think how we would repeat any data item N times recursively:

If times is 0 or less, we return an empty list, as per the requirements.
If times is greater than 0, we return list that has data ones and another times - 1 repetitions of data, recursively. 

Another requirement is to check the validity of the arguments and raise a ValueError if they are invalid. While this can be done in the same recursive function, this carries a performance hit, as we'll do the same validation times times. The textbook solution for this is to separate the function to two - an "outer" function that handles the validations and and "inner" function that handles the recursive logic. 
Put it all together, and you'll get something like this:
def replicate_recur(times, data):
    if not isinstance(times, int):
        raise ValueError("times must be an int")

    return real_replicate_recur(times, data)

def real_replicate_recur(times, data):
    if times <= 0:
        return []

    return [data] + real_replicate_recur(times - 1, data)

