Data-store failure please help!

I have a pretty basic datastore script which was working until I added some more things, so that made me think to just split it into another script but I didn’t know if it was something else?

local DataStoreService=game:GetService("DataStoreService")
local DataStore=DataStoreService:GetDataStore("NinjaRevelationsV5")
game.Players.PlayerAdded:connect(function(player)
	--Ok get ready, it's time to set the values up!
	local getSave; 	
	local level = Instance.new("IntValue", player)
	level.Name = "level"
	
	local ninjutsu = Instance.new("IntValue", player)
	ninjutsu.Name = "ninjutsu"
	
	local genjutsu = Instance.new("IntValue", player)
	genjutsu.Name = "genjutsu"
	
	local taijutsu = Instance.new("IntValue", player)
	taijutsu.Name = "taijutsu"
	
	local chakra = Instance.new("IntValue", player)
	chakra.Name = "chakra"
	
	local speed = Instance.new("IntValue", player)
	speed.Name = "speed"
	
	local skillPoints = Instance.new("IntValue", player)
	skillPoints.Name = "skillPoints"
	
	local exp = Instance.new("IntValue", player)
	exp.Name = "exp"
	
	local throwable = Instance.new("StringValue", player)
	throwable.Name = "throwable"
	
	local ryo = Instance.new("IntValue", player)
	ryo.Name = "ryo"
	
	local weapon = Instance.new("StringValue", player)
	weapon.Name = "weapon"
	
	local firstName = Instance.new("StringValue", player)
	firstName.Name = "firstName"
	
	local lastName = Instance.new("StringValue", player)
	lastName.Name = "lastName"
	
	local inMenu = Instance.new("BoolValue", player)
	inMenu.Name = "inMenu"
	inMenu.Value = true
	
	local inCharacterCustomization = Instance.new("BoolValue", player)
	inCharacterCustomization.Name = "inCharacterCustomization"
	inCharacterCustomization.Value = false
	
	local hasCharacter = Instance.new("BoolValue", player)
	hasCharacter.Name = "hasCharacter"
	
	
	------------------CHARACTER CUSTOMIZATION------------------------------
	
	local face = Instance.new("IntValue", player)
	face.Name = "face"
	
	local hair = Instance.new("IntValue", player)
	hair.Name = "hair"
	
	local headband = Instance.new("IntValue", player)
	headband.Name = "headband"
	
	local clothing = Instance.new("IntValue", player)
	clothing.Name = "clothing"
	
	local accessory1 = Instance.new("IntValue", player)
	accessory1.Name = "accessory1"
	
	local accessory2 = Instance.new("IntValue", player)
	accessory2.Name = "accessory2"
	
	local skinTone = Instance.new("IntValue", player)
	skinTone.Name = "skinTone"
	
	local faceColor = Instance.new("Color3Value", player)
	faceColor.Name = "faceColor"
	
	local hairColor = Instance.new("Color3Value", player)
	hairColor.Name = "hairColor"
	
	local headbandColor = Instance.new("Color3Value", player)
	headbandColor.Name = "headbandColor"
	------------------LEVEL 1 JUTSU------------------------------
	
	local fire1 = Instance.new("BoolValue", player)
	fire1.Name = "fire1"
	
	local earth1 = Instance.new("BoolValue", player)
	earth1.Name = "earth1"
	
	local wind1 = Instance.new("BoolValue", player)
	wind1.Name = "wind1"
	
	local water1 = Instance.new("BoolValue", player)
	water1.Name = "water1"
	
	local lightning1 = Instance.new("BoolValue", player)
	lightning1.Name = "lightning1"
	
	
	player.CanLoadCharacterAppearance = false
	------------------------------------------------
	local CanSave=Instance.new('BoolValue',player) 
	                                  
	CanSave.Name="CanSaveData"
	CanSave.Value=true
	
	
	local DataFetchSuccess,ErrorMessage=pcall(function() --We are wrapping the datastore request in a protected function, as web requests can error. 
		getSave=DataStore:GetAsync("NR_"..player.userId)
	end)
	if DataFetchSuccess then --The datastore GET request was successful!
		
		if getSave~=nil then --The player's data exists, they have played this game before. Put their data into the leaderboard.
			level.Value = getSave.level
			ninjutsu.Value = getSave.ninjutsu
			genjutsu.Value = getSave.genjutsu
			taijutsu.Value = getSave.taijutsu
			chakra.Value = getSave.chakra
			speed.Value = getSave.speed
			skillPoints.Value = getSave.skillPoints
			exp.Value = getSave.exp
			throwable.Value = getSave.throwable
			ryo.Value = getSave.ryo
			weapon.Value = getSave.weapon
			firstName.Value = getSave.firstName
			lastName.Value = getSave.lastName
			------------------CUSTOMIZATION------------------------------
			hasCharacter.Value = getSave.hasCharacter
			face.Value = getSave.face
			hair.Value = getSave.hair
			headband.Value = getSave.headband
			clothing.Value = getSave.clothing
			accessory1.Value = getSave.accessory1
			accessory2.Value = getSave.accessory2
			skinTone.Value = getSave.skinTone
			hairColor.Value = getSave.hairColor
			faceColor.Value = getSave.faceColor
			headbandColor.Value = getSave.headbandColor
			------------------LEVEL 1 JUTSU------------------------------
			fire1.Value = getSave.fire1
			water1.Value = getSave.water1
			lightning1.Value = getSave.lightning1
			earth1.Value = getSave.earth1
			wind1.Value = getSave.wind1
			------------------LEVEL 2 JUTSU------------------------------
			--[[if getSave.starter ~= nil then
				starter.Value = getSave.starter
			end]]
			
			--Questing
		else --The player's data does not exist, they're new to the game. Create their data on the leaderboard.
			level.Value = 1
			ninjutsu.Value = 1
			genjutsu.Value = 1
			taijutsu.Value = 1
			chakra.Value = 1
			speed.Value = 1
			skillPoints.Value = 0
			exp.Value = 0
			throwable.Value = "Shuriken"
			ryo.Value = 0
			weapon.Value = "None"
			firstName.Value = ""
			lastName.Value = ""
			------------------CUSTOMIZATION------------------------------
			hasCharacter.Value = false
			face.Value = 1
			hair.Value = 1
			headband.Value = 1
			clothing.Value = 1
			accessory1.Value = 1
			accessory2.Value = 1
			skinTone.Value = 1
			hairColor.Value = BrickColor.new("Black").Color
			faceColor.Value = BrickColor.new("Really black").Color
			headbandColor.Value = BrickColor.new("Black").Color
			------------------LEVEL 1 JUTSU------------------------------
			fire1.Value = false
			water1.Value = false
			lightning1.Value = false
			earth1.Value = false
			wind1.Value = false
		end
	else --The GET request failed, datastores could be down.
		player.CanSaveData.Value=false
		player:Kick("Your data failed to load! Please rejoin(This occured due to lag).")	
	end
  
end)
--[[
	A player is leaving the game. Save their data.
--]]
--Cameron remember player removing does not fire on leave in TEST MODE
game.Players.PlayerRemoving:connect(function(player)
	print("Beginning to save "..player.Name)
	if player.CanSaveData.Value==false then print(player.Name.." HAS FAILED VALUE") return end --Player data can't be saved, so do nothing.
	print(player.Name.." has passed can save val")
	local afterSave = {
		level = player.level.Value,  
		ninjutsu = player.ninjutsu.Value,  
		genjutsu = player.genjutsu.Value,  
		taijutsu = player.taijutsu.Value,  
		chakra = player.chakra.Value,  
		speed = player.speed.Value,  
		skillPoints = player.skillPoints.Value,  
		exp = player.exp.Value,  
		throwable = player.throwable.Value,
		ryo = player.ryo.Value,
		weapon = player.weapon.Value,
		firstName = player.firstName.Value,
		lastName = player.lastName.Value,
		fire1 = player.fire1.Value,
		water1 = player.water1.Value,
		lightning1 = player.lightning1.Value,
		earth1 = player.earth1.Value,
		wind1 = player.wind1.Value,
		hasCharacter = player.hasCharacter.Value,
		face = player.face.Value,
		hair = player.hair.Value,
		headband = player.headband.Value,
		clothing = player.clothing.Value,
		accessory1 = player.accessory1.Value,
		accessory2 = player.accessory2.Value,
		skinTone = player.skinTone.Value,
		hairColor = player.hairColor.Value,
		faceColor = player.faceColor.Value,
		headbandColor = player.headbandColor.Value,
	}
	--[[
		
	]]
	local DataWriteSuccess,ErrorMessage=pcall(function() --Once again, we are safely calling a web request. If it fails, we can safely handle it.
		DataStore:SetAsync("NR_"..player.userId, afterSave)
	end)	
	if DataWriteSuccess then
		print(player.Name.." HAS HAD THEIR DATA SUCCESSFULLY SAVED!")
	end
	if not DataWriteSuccess then --Uh oh, player data didnt' save. Handle this error.
		--We will attempt to save the player's data 5 more times. If it fails after 5 times, 
		--we will abort the save and the player's data will not be changed in the datastores.
		print("DATA SAVE HAS FAILED TRYING AGAIN")
		local Retry_Count=0
		
		while Retry_Count<6 do
			wait(60) --Wait 1 minute between each retry
			local Succeded,Error=pcall(function()
				DataStore:SetAsync("NR_"..player.userId, afterSave)
			end)
			if Succeded then print("SECONDARY SAVE SUCCESSFUL") break end --HURRAY, DATA SAVED!
			Retry_Count=Retry_Count+1
		end
		
	end
	
end)
--[[while wait(35) do
	for i, player in pairs(game.Players:GetChildren()) do
		if player.CanSaveData.Value==false then return end
		print(player.Name.." Is having their player data saved")
		local afterSave = {
			level = player.level.Value,  
			ninjutsu = player.ninjutsu.Value,  
			genjutsu = player.genjutsu.Value,  
			taijutsu = player.taijutsu.Value,  
			chakra = player.chakra.Value,  
			speed = player.speed.Value,  
			skillPoints = player.skillPoints.Value,  
			exp = player.exp.Value,  
			throwable = player.throwable.Value,
			ryo = player.ryo.Value,
			weapon = player.weapon.Value,
			firstName = player.firstName.Value,
			lastName = player.lastName.Value,
			fire1 = player.fire1.Value,
			water1 = player.water1.Value,
			lightning1 = player.lightning1.Value,
			earth1 = player.earth1.Value,
			wind1 = player.wind1.Value,
			hasCharacter = player.hasCharacter.Value,
			face = player.face.Value,
			hair = player.hair.Value,
			headband = player.headband.Value,
			clothing = player.clothing.Value,
			accessory1 = player.accessory1.Value,
			accessory2 = player.accessory2.Value,
			skinTone = player.skinTone.Value,
			hairColor = player.hairColor.Value,
			faceColor = player.faceColor.Value,
			headbandColor = player.headbandColor.Value,
		}
		local DataWriteSuccess,ErrorMessage=pcall(function() --Once again, we are safely calling a web request. If it fails, we can safely handle it.
			DataStore:SetAsync("NR_"..player.userId, afterSave)
		end)
		if not DataWriteSuccess then --Uh oh, player data didnt' save. Handle this error.
		--We will attempt to save the player's data 5 more times. If it fails after 5 times, 
		--we will abort the save and the player's data will not be changed in the datastores.
		
		local Retry_Count=0
		
		while Retry_Count<6 do
			wait(60) --Wait 1 minute between each retry
			local Succeded,Error=pcall(function()
				DataStore:SetAsync("NR_"..player.userId, afterSave)
			end)
			if Succeded then break end --HURRAY, DATA SAVED!
			Retry_Count=Retry_Count+1
		end
		
	end
	end
end]]

Output after 2 save attempts:
image

If you wrap it in a pcall next time and this happens, the pcall will be the only thing that breaks, not the entire script. I’m new to programming so correct me if I’m wrong :sweat_smile:

Oh yea my bad :flushed:


What’s a UTF-8 character?

Couldn’t tell you, I suck at scripting. Sorry! I’m still learning.

I’m moderately advanced at scripting I just rarely work with Datastore and am on guard based on how important it is

UTF-8 is simply a near-universal character encoding scheme that was invented to solve problems of transferring data between computers back when the internet was just becoming a thing.

This error indicates that you’re attempting to store something that isn’t a valid UTF-8 encoded character. In this case, it seems that accessory2 (the thing being set on line 239) isn’t a valid UTF-8 character. I’m trying to figure out why. If I do, I’ll respond again.

I thought it was me trying to save colors

After some testing, it appears that there are three values that the DataStoreService doesn’t like. In your afterSave table, these values are:

  • hairColor
  • faceColor
  • headbandColor

Through some debugging techniques I’ve learned (aka lots of print statements), it appears these values are a set of three numbers. When the DataStoreService receives these values and attempts to serialize them for storage, it appears to error; my theory is that the DataStoreService simply doesn’t know what to do with these values, and defaults to returning an error for the developer to handle.

If you haven’t already, you can probably solve this by using a dictionary within your afterSave dictionary to store the three above values. (There are probably other options, such as store these values within a Tuple, but I don’t recall if tuples can be created be the developer.)

As an aside, my second paragraph in my first reply isn’t true. Whenever I’m debugging, if I see an error occur, I look mainly for an error message and line number within the traceback. This is one instance where the line number referenced had nothing to do with your code, as the traceback was referencing an internal function of the DataStoreService.

Your theory is correct! You can only save UTF-8 characters and Color3 values are simply not anything like that. There is no serialization that happens by default (save for basic web encoding) so all Roblox instances and custom values result in an error as they just simply don’t exist outside of Roblox. Datastores are very similar to JSON so anything you can’t store in a standard JSON file you can’t store in a Datastore

You can serialize your data by using HTTPService or just by saving the RGB values as separate integers and then putting them back together in loading.


Tuples can be created by developers. Return them from a function as you would normally.

function foo()
return true, false, true
end
2 Likes

So basically I have to save the HSV and remake that each time :expressionless: