A UDN user found that calling
while the gameplay tag was not in the TagMap, will create an entry for it with count 0, see FMinimalReplicationTagCountMap::RemoveTag. Then, since FMinimalReplicationTagCountMap::NetSerialize serializes all keys without regard for count, simulated proxies will think the tag is in the map.
I was able to repro this behavior 100% with the actor code shared under repro steps.
Create an actor as below, with TagToRemove being an UPROPERTY(EditAnywhere) FGameplayTag that's set to a valid tag:
At runtime, the server will "remove" a tag but instead this will add an entry into the replicated TagMap with count 0. On the client, HasMatchingGameplayTag then evaluates to true. Once fixed, it should correctly evaluate to false on the client.
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-170468 in the post.