How can I test for a nonexistant NBT tag?

I have three villagers, which might or might not have a custom name.

The custom name is controlled by the CustomName NBT tag.

For villagers with a custom name, their CustomName tag looks like this:

{CustomName:'{"text":"Chad Ferguson"}'}

For villagers without a custom name, the CustomName tag is nonexistant.

Here is some code to test for if a villager has a certain name (using the nbt argument):

/execute if entity @e[type=villager,nbt={CustomName:'{"text":"Chad Ferguson"}'}] run tellraw @a {"text":"Chad is here!"}

Now I would like to test for an entity with a nonexistant CustomName tag, something like this:

/execute if entity @e[type=villager,nbt={CustomName:''}] run tellraw @a {"text":"An unknown villager is near"}

Now, this command won't work, because an existing, empty string is different from the tag not existing.

The ! argument won't work, because of this:

execute
  if entity @e[type=villager,nbt=!{CustomName:''}]    # If there is an entity that does not have an empty custom name...
run tellraw @a {"text":"An unknown villager is near"} # then say a message.

That command will run if the tag is nonexistant or if the tag has something other than an empty string ''.

How can I test for entities with a nonexistant NBT tag? I am in MCJE 1.16.2.


Solution 1:

Use this command:

execute
  as @e[type=villager]           # Tell all the villagers to run the following:
  store success score @s nbtTest # Store the success/failure of the final command to run here in a scoreboard.
run data get @s CustomName       # Get my custom name.

This will make all the villagers run the /data command to get their custom name.

And here's where the magic happens: the command passes if the tag exists, and fails if it doesn't. And since we're storing the success/failure in the scoreboard, we can just look: any entities with scoreboard value 0 have a nonexistant CustomName tag!