The problem is that you are piping the output of ps into a call to awk that looks for the string "Xvfb" and therefore also contains the string "Xvfb" in its own command-line. Because both processes of a pipe are executed simultanously, the awk call itself will also register in the output of ps (try what happens if you just type ps -ef | awk '/Xvfb/' on the command-line).
However, by the time the loop is started (which happens when the command-substitution $( … ) and therefore the awk process, too, has exited), this awk process doesn't exist anymore, hence kill stumbles upon this.
You should be safe if you modify the command in the command substitution to
ps -ef | awk '$0 ~ /Xvfb/ && index($0,"awk")==0 {print $2}' which will ensure that no command containing the substring awk are included in the list. Note that you should quote your shell variables, as well as the command-substitution, with double-quotes.