Why is DEFAULT_DATA being written to?

Recently, I wrote up a quick data store module for a small game I’m working on. Everything seemed to be working as fine until I noticed that some players data where being duplicated. Upon further investigation, I found out that my supposed to be constant value, DEFAULT_DATA was being written too somehow. After searching through all my scripts for the potential cause I’m still left scratching my head.

Is there some obscure table/dictionary behaviour here that I’m not aware of?

Here’s the simplified version of my scripts which isolate the issue:

The data module itself

local DataModule = {}

local DataStoreService = game:GetService("DataStoreService")
local USER_DATA_STORE = DataStoreService:GetDataStore("UserData")

local storedData = {}

local DEFAULT_DATA = {
	TestTable = {};
	Money = 0
}
table.freeze(DEFAULT_DATA)

local function _getDefaultData ()
	local data = {}

	for key, value in DEFAULT_DATA do
		data[key] = value
	end

	return data
end

function DataModule.get (player)
	print("Default data = ", DEFAULT_DATA)
	if storedData[player.UserId] then return storedData[player.UserId] end

	storedData[player.UserId] = _getDefaultData()
	return storedData[player.UserId]
end

return DataModule

The script that’s reading and writing data

local ServerScriptService = game:GetService("ServerScriptService")
local Players = game:GetService("Players")

local DataModule = require(ServerScriptService.DataModule)

local function playerAdded (player)
	local data = DataModule.get(player)
	
	data.TestTable.TestValue = 100
	data.Money = 100

	data = DataModule.get(player)
	
	print("User data = ", data)
end

Players.PlayerAdded:Connect(playerAdded)

What gets outputted

Note how money isn’t written to, only TestTable, which proves that it’s not just a simple reference to default data but rather its own table.

why is the TestTable value in DEFAULT_DATA being written to?

Any and all help is appreciated!

You’re creating a shallow copy of the default table. You have to create a deep copy of the table, so that the nested tables under it will also be copied. Otherwise, you’re just creating references to them.

Aw that’s right. Pretty tired so forgot deep copies where a thing lol. Thanks for the speedy reply.