You have two issues in your code. First, you ask for new input, update row, but then only check ch without changing it. If you trace the code line by line you can see what I mean. ch can never change once you get bad input. That's the issue you're describing. You can easily see this if you add the the character that doesn't match to your error message.
print("ERROR: please enter valid characters --", ch)
The second issue is that your code assumes changing row will restart the loop and read its new values. You can see how that won't work with this example:
some_list = [1,2,3,4,5]
for i in some_list:
print(i)
if i == 2:
some_list = ['a', 'b', 'c']
You expect this example to print:
1
2
a
b
c
But it will print:
1
2
3
4
5
When you assign a new value to row, the loop will keep running over its old value because it already read the value.
Both issues can be found by tracing your code line by line. You can use a debugger, trace it in your head, or add print() statements everywhere to see what happens.
To get this working, you can use something like the following. There are better and cleaner ways to do it, but it should convey the expected logic.
valid_char = ["k", "q", "r", "n", "b", "p", "K", "Q", "R", "N", "B", "P", "-"]
while True:
row = input()
all_valid = True
for ch in row:
if ch not in valid_char: #validating input characters
print("\nERROR: please enter valid characters")
all_valid = False
break
if all_valid:
print('valid!')
break
while ch not in...You wantif ch not in...and to move the authentication loop outside of theforloop.row = input()is inside awhileloop, which should just be a conditional branch isntead...row, you're stuck in thewhile ch not in valid_charloop, with neitherchnorvalid_charchanging.chis not invalid_charthenwhile ch not in valid_char:stars looping and it can't leave this loop becausechdoesn't change - it compare again the samechwhich is not invalid_char. You would have to changechinsidewhilefor value fromvalid_charto leave loop. Maybe useprint('ch:', ch)in different places.