Sending mixed tables through remotes or bindables is not supported on Roblox.
To fix this, you’ll need to change the format of your data to avoid mixed tables.
Let’s dig into what that means.
What is a mixed table?
In Lua, think of there being two kinds of tables.
-
Dictionary: Keys may be anything. Imagine finding a word (key) in a physical dictionary and looking up its definition (value).
-
Array: Keys must be numbers starting from 1 and counting up, with no holes. The first
null
value indicates the END of the array. Imagine an ordered list (array) of things.
For example, when you define a table like this, e.g. as an array:
Array
{
"hi",
"world",
}
that’s syntactic sugar for this equivalent dictionary-style definition:
Also an array, but shown like a dictionary
{
[1] = "hi",
[2] = "world",
}
A dictionary that is not an array looks like this:
Dictionary
{
hi = "world",
}
which, by the way, is the same thing as
Dictionary (alternate)
{
["hi"] = "world"
}
So both arrays and dictionaries are technically the same type under the hood, but certain Lua functions give special treatment to arrays.
For example, in an array with keys counting from 1 to n
, ipairs
will stop iterating at n
even if n+2
exists, or even if a non-numeric key exists. Similarly, the #
operator will only count items up to n
. This is also why you can’t use #
on a dictionary!
A mixed table is a table that contains both styles of keys.
Usually, you want to write your code to avoid this kind of table since it creates exactly the kind of confusion you’re having now.
Why mixed tables are causing you problems
Now that we understand tables formatted as arrays vs dictionaries, let’s look at why it’s causing you problems.
Setting up your table
In your code, you first define your Effects
table with a dictionary-style index Equipped
, creating essentially this in a server script:
local playerdata = {
Effects = {
Equipped = {}, -- Effects contains Equipped, a dictionary key
},
}
Verifying the setup
If you print playerdata.Effects
now from the same server script with log mode
of the output off, this calls a Roblox function under the hood to “pretty print” your table, giving you this output:
Command (server script)
print(playerdata.Effects)
Output (server)
{
["Equipped"] = {}
}
Nice! It includes Equipped
just as expected.
Create the mixed table
Later, you use table.insert
to add the item into the Effects
table.
table.insert(playerdata.Effects, "Gamer")
Let’s re-run the print commands from earlier.
Command (server script)
print(playerdata.Effects)
Output (server)
{
[1] = "Gamer",
["Equipped"] = {}
}
Woah - we see the same “Equipped” key as before, but now there’s also a 1
key! That’s because table.insert
treats it like an array, and it sees the lowest non-nil numeric index is [1], so it inserts the value there.
We now have a mixed table, where part of it is defined as an array and another part is defined as a dictionary.
But so far, this is expected! This looks good! What about your problem, where the Equipped
table is going away?
Replicating the problem
You have the player’s inventory stored in a server script, but you need your client script to have access to it. So, naturally, you send it to your client script using a Remote Event.
Something similar to:
Code (server script)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local replicateInventory = ReplicatedStorage.ReplicateInventoryRemoteEvent
...
print(playerdata) -- this is the print from earlier. Everything was fine.
replicateInventory:FireClient(somePlayer, playerdata)
And on the client, you have something like:
Code (client script)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local replicateInventory = ReplicatedStorage.ReplicateInventoryRemoteEvent
replicateInventory.OnClientEvent:Connect(function(playerdata)
print(playerdata.Effects) -- Let's print what the client receives
end)
On the client, the print outputs this:
Output (client)
{
[1] = "Gamer"
}
AHA!
It happened! Equipped
is gone from the Effects
table! But it was just there on the server! Here, you encounter a limitation of Roblox. As stated at the top of this post, Roblox does not support sending mixed tables through Remote Events/Functions, or even through Bindable events/functions for that matter.
The reason is because bindables and remotes pass your data through a C++ backend which doesn’t keep mixed tables. I assume this hasn’t been “fixed” in order to avoid breaking legacy games that depend on this behavior.
Anyway, as stated at the top of this post, you need to change the way you define your data to avoid mixed tables to fix your problem. 
For example, a schema like this would work because on a per-table basis, keys are always either array-style OR dictionary-style, but never both in the same table:
local playerdata = {
Effects = {
Owned = {
"item1",
"item6",
"item5",
"item7",
"item2",
},
Equipped = {
"item5",
"item1",
}
},
Trails = {
...
},
...
}