RewriteCond %{QUERY_STRING} ^?afe([^&]*)
RewriteCond %{QUERY_STRING} !=""
RewriteRule (.*) /$1%3F%{QUERY_STRING}? [L]
The QUERY_STRING server variable does not contain the ? itself (query string delimiter). However, the regex ^?afe([^&]*) is entirely invalid (the ? is a regex quantifier and ^ is not quantifiable) so this would/should result in a 500 Internal Server Error since the regex cannot be compiled. (Although you say you are getting a 404, so is this rule even being processed?!)
There's no need to check that the query string is not empty (second condition) when you have already established that there is a query string that matches the pattern (in the first condition).
Try the following instead:
RewriteCond %{QUERY_STRING} ^afe/[^&]+\.doc$
RewriteRule ^(uploads/.+) $1\%3F%{QUERY_STRING} [NE,QSD,L]
Note that the % before 3 must be backslash-escaped to avoid it being treated as a numeric backreference (which would otherwise be empty).
I removed the slash prefix on the substitution string so it would be treated as a relative file-path, as opposed to a URL-path (unless you have a RewriteBase directive set).
The QSD (Query String Discard) flag is the preferred way to discard the original query string from the request on Apache 2.4, rather than appending an empty query string (trailing ?) which would have been required on earlier versions of Apache.
QUERY_STRINGcontains the question mark, as your own regex tests. You then embed this after%3F. Seems one question mark too many, no?QUERY_STRINGserver var does not contain the question mark, which is part of the problem.