[SPIGOT-583] Custom Player Skull Texture NPE on Serialize Created: 17/Feb/15  Updated: 22/Jul/15  Resolved: 07/Jun/15

Status: Closed
Project: Spigot
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Minor
Reporter: Nathan Wolf Assignee: Thinkofname
Resolution: Fixed Votes: 3
Labels: None


 Description   

It is possible, with vanilla commands, to give yourself a player skull without a profile attached, that contains a custom texture. See here:

http://www.dragnoz.com/custom-head-block-generator/

When serializing such an item, an NPE is thrown.

I realize this is kind of a hacky thing to do, but as long as it works it'd be nice if it was supported.



 Comments   
Comment by md_5 [ 22/Jul/15 ]

Might be best to open a new ticket.

Comment by blablubbabc [ 22/Jul/15 ]

Any update on this one? Just wanting to let you know that I am as well still getting reports of users still having this issue.

Edit: The issue is probably caused by skull items with a profile which only has an uuid and no name.
So the first part of the issue is trying to store null in the ImmutableMapBuilder here (which doesn't accept null as value): https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/browse/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java#159

The second part of the issue would then be to properly store and restore the profile uuid (which doesn't currently get stored as far as I can tell from a quick look at the source code).

Comment by Nathan Wolf [ 24/Jun/15 ]

Hmm.. yeah looking at the code, I think the fix for this handled saving the full profile (yay!) but still tries to separately save the owner name, I'm guessing for backwards-compatibility.

A simple check for null before adding owner name to the serialization map would probably fix this.

Comment by Robert Pettit [ 24/Jun/15 ]

Has this fix been pushed? I still can't save a yml file that has one of these custom heads. I am running the latest version of spigot and have recompiled my plugin with the same spigot.
"...git-Spigot-f928e7a-994b2aa (MC: 1.8.7) (Implementing API version 1.8.7-R0.1-SNAPSHOT)" [via: /version]

Here is the Stacktrace I get when the plugin tries to save the .yml

Stacktrace1
2015-06-24 15:33:24 | [ERROR] Could not pass event InventoryClickEvent to AuctionHouse v1.0
2015-06-24 15:33:24 | [RAW] org.bukkit.event.EventException
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:310) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:502) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:487) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.PlayerConnection.a(PlayerConnection.java:1603) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.PacketPlayInWindowClick.a(SourceFile:31) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.PacketPlayInWindowClick.a(SourceFile:9) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.PlayerConnectionUtils$1.run(SourceFile:13) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_45]
2015-06-24 15:33:24 | [RAW] ?at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_45]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.SystemUtils.a(SystemUtils.java:19) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:718) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:367) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:657) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:560) [spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at java.lang.Thread.run(Thread.java:745) [?:1.8.0_45]
2015-06-24 15:33:24 | [RAW] Caused by: java.lang.NullPointerException: null value in entry: skull-owner=null
2015-06-24 15:33:24 | [RAW] ?at com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:33) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at com.google.common.collect.ImmutableMap.entryOf(ImmutableMap.java:135) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at com.google.common.collect.ImmutableMap$Builder.put(ImmutableMap.java:206) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.craftbukkit.v1_8_R3.inventory.CraftMetaSkull.serialize(CraftMetaSkull.java:173) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.craftbukkit.v1_8_R3.inventory.CraftMetaItem.serialize(CraftMetaItem.java:850) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSerializable.representData(YamlRepresenter.java:33) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:94) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:156) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:304) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSerializable.representData(YamlRepresenter.java:35) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:94) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:156) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:304) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSection.representData(YamlRepresenter.java:23) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:94) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:156) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:304) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSection.representData(YamlRepresenter.java:23) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:94) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:156) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:304) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:94) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.representer.BaseRepresenter.represent(BaseRepresenter.java:64) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:242) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:206) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.yaml.snakeyaml.Yaml.dump(Yaml.java:181) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.configuration.file.YamlConfiguration.saveToString(YamlConfiguration.java:40) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.configuration.file.FileConfiguration.save(FileConfiguration.java:103) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?at me.surfdudeboy.auctionhouse.YMLIO.save(YMLIO.java:904) ~[?:?]
2015-06-24 15:33:24 | [RAW] ?at me.surfdudeboy.auctionhouse.objects.AuctionListing.<init>(AuctionListing.java:68) ~[?:?]
2015-06-24 15:33:24 | [RAW] ?at me.surfdudeboy.auctionhouse.GUI.SellDialogue.createListing(SellDialogue.java:63) ~[?:?]
2015-06-24 15:33:24 | [RAW] ?at me.surfdudeboy.auctionhouse.GUI.Listeners.Execute.manipulateNewListingPage(Execute.java:183) ~[?:?]
2015-06-24 15:33:24 | [RAW] ?at me.surfdudeboy.auctionhouse.GUI.Listeners.AuctionListeners.onGUIInteract(AuctionListeners.java:89) ~[?:?]
2015-06-24 15:33:24 | [RAW] ?at sun.reflect.GeneratedMethodAccessor63.invoke(Unknown Source) ~[?:?]
2015-06-24 15:33:24 | [RAW] ?at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
2015-06-24 15:33:24 | [RAW] ?at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
2015-06-24 15:33:24 | [RAW] ?at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:306) ~[spigot.jar:git-Spigot-f928e7a-994b2aa]
2015-06-24 15:33:24 | [RAW] ?... 15 more 

There is also sometimes a stacktrace printed when moving the head around inside of a chest.

stacktrace2
2015-06-24 15:52:11 | [WARN] java.lang.NullPointerException: null value in entry: skull-owner=null
2015-06-24 15:52:11 | [WARN] ?at com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:33)
2015-06-24 15:52:11 | [WARN] ?at com.google.common.collect.ImmutableMap.entryOf(ImmutableMap.java:135)
2015-06-24 15:52:11 | [WARN] ?at com.google.common.collect.ImmutableMap$Builder.put(ImmutableMap.java:206)
2015-06-24 15:52:11 | [WARN] ?at org.bukkit.craftbukkit.v1_8_R3.inventory.CraftMetaSkull.serialize(CraftMetaSkull.java:173)
2015-06-24 15:52:11 | [WARN] ?at org.bukkit.craftbukkit.v1_8_R3.inventory.CraftMetaItem.serialize(CraftMetaItem.java:850)
2015-06-24 15:52:11 | [WARN] ?at net.coreprotect.database.Logger.container_logger(Logger.java:498)
2015-06-24 15:52:11 | [WARN] ?at net.coreprotect.database.Logger.log_container(Logger.java:413)
2015-06-24 15:52:11 | [WARN] ?at net.coreprotect.consumer.Process.processContainerTransaction(Process.java:251)
2015-06-24 15:52:11 | [WARN] ?at net.coreprotect.consumer.Process.processConsumer(Process.java:91)
2015-06-24 15:52:11 | [WARN] ?at net.coreprotect.consumer.Consumer.run(Consumer.java:49)
2015-06-24 15:52:11 | [WARN] ?at java.lang.Thread.run(Thread.java:745)

The skull is obtained through the following command via command block: Note that The SkullOwner was assigned to an arbitrary, random UUID. This is done to prevent new custom skulls from overwriting the texture of others.

command
/give @p skull 1 3 
{display:{Name:"Dallas Mask"},
	SkullOwner:{
		Id:"60dbfcd2-4f2e-49ff-91ed-e8e6242dd0b2",
		Properties:{
			textures:
			[{
				Value:
"eyJ0aW1lc3RhbXAiOjE0MzA2MTYwMTM2ODMsInByb2ZpbGVJZCI6IjNjZTY4YzY0OTg3NDQ4ZmRiOGIyMjZhOTk2M2M1ZjcyIiwicHJvZmlsZU5hbWUiOiJTdXJmZHVkZWJveSIsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9lNzM3ZWU1NTcwNGE2ZjRlYWMxOGJmZWVlMjIyZDc2Zjc5OWQyNGQ3MzAzNjc3NzRhNTFiZjkxYWQzYzJjIn19fQ=="
			}]
		}
	}
}
Comment by Nathan Wolf [ 07/Jun/15 ]

Did this get fixed by saving the full player profile? I'm guessing not ... But hopefully asking anyway

Comment by Nathan Wolf [ 19/Feb/15 ]

No problem! I could've been more clear about the specific part that was broken.

For the most part, the custom skulls seem to work- but if you think "oh, these are awesome, players would love to buy them", and try to put one in a shopkeeper- it will blow up on save and delete all your Shopkeepers. Same with StarterKit, or I imagine any other plugin that tries to serialize items when it saves data.

Comment by Nathan Wolf [ 19/Feb/15 ]

I guess I should also mention I have a PR submitted to fix this. It relies on one of my other PR's though (for general serialization of NBT data)

Comment by Nathan Wolf [ 19/Feb/15 ]

Here's an example stack trace of this in action, something I should have provided originally!

[10:18:47] [Craft Scheduler Thread - 8/WARN]: org.apache.commons.lang.UnhandledException: Plugin Shopkeepers v1.43 generated an exception while executing task 10138
	at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:56)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: null value in entry: skull-owner=null
	at com.google.common.collect.CollectPreconditions.checkEntryNotNull(CollectPreconditions.java:33)
	at com.google.common.collect.ImmutableMap.entryOf(ImmutableMap.java:135)
	at com.google.common.collect.ImmutableMap$Builder.put(ImmutableMap.java:206)
	at org.bukkit.craftbukkit.v1_8_R1.inventory.CraftMetaSkull.serialize(CraftMetaSkull.java:150)
	at org.bukkit.craftbukkit.v1_8_R1.inventory.CraftMetaItem.serialize(CraftMetaItem.java:810)
	at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSerializable.representData(YamlRepresenter.java:33)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:157)
	at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:320)
	at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSerializable.representData(YamlRepresenter.java:35)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:157)
	at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:320)
	at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSection.representData(YamlRepresenter.java:23)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:157)
	at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:320)
	at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSection.representData(YamlRepresenter.java:23)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:157)
	at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:320)
	at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSection.representData(YamlRepresenter.java:23)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:157)
	at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:320)
	at org.bukkit.configuration.file.YamlRepresenter$RepresentConfigurationSection.representData(YamlRepresenter.java:23)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representMapping(BaseRepresenter.java:157)
	at org.yaml.snakeyaml.representer.SafeRepresenter$RepresentMap.representData(SafeRepresenter.java:320)
	at org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.java:95)
	at org.yaml.snakeyaml.representer.BaseRepresenter.represent(BaseRepresenter.java:65)
	at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:271)
	at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:262)
	at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:234)
	at org.yaml.snakeyaml.Yaml.dump(Yaml.java:209)
	at org.bukkit.configuration.file.YamlConfiguration.saveToString(YamlConfiguration.java:40)
	at com.nisovin.shopkeepers.ShopkeepersPlugin.saveDataToFile(ShopkeepersPlugin.java:1128)
	at com.nisovin.shopkeepers.ShopkeepersPlugin.access$900(ShopkeepersPlugin.java:54)
	at com.nisovin.shopkeepers.ShopkeepersPlugin$10.run(ShopkeepersPlugin.java:1087)
	at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftTask.run(CraftTask.java:71)
	at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
	... 3 more
Comment by Nathan Wolf [ 19/Feb/15 ]

The NPE arises when you serialize the items.

This is because they are lacking a "Name" NBT tag, and CraftMetaSkull assumes it's there.

This can be worked around by just putting some random name in there, but the skull will then revert to that player's skull after serializing + deserializing.

Comment by David McKenna [ 19/Feb/15 ]

Using the default one they provided in the video ( https://i.imgur.com/ggXlehE.png ) with that tool, I cannot replicate your NPE and the skeleton spawns fine / item is given to me textured on git-Bukkit-3fc97ff

http://i.suddenly.coffee/2015-02-19_15.13.55.png
http://i.suddenly.coffee/2015-02-19_15.16.42.png

EDIT: Misread, sorry.

Generated at Thu Jul 07 02:16:52 UTC 2022 using Jira 9.0.0#900003-sha1:3a66c72723fa5e73f2191cdfc1f1b28a5950171c.