getrawmetatable
Retrieves the actual metatable of any object, bypassing __metatable locks.
function getrawmetatable(object: any): tableSynopsis
How it works
Normally,
getmetatable(obj) checks for a __metatable field and returns that decoy instead of the real metatableMetatableA table attached to another table (or userdata) that defines operator overloading via metamethods (__index, __newindex, __call, etc.). Roblox Instances use shared read-only metatables for method dispatch.. getrawmetatable bypasses this by directly reading the internal metatable pointer on the Luau Table or Udata struct, ignoring the __metatable metamethodMetamethodA function in a metatable that overrides default behavior for operations like indexing (__index), assignment (__newindex), calling (__call), comparison (__eq), and arithmetic (__add, __mul, etc.). entirely.VM internals — struct layout
The metatableMetatableA table attached to another table (or userdata) that defines operator overloading via metamethods (__index, __newindex, __call, etc.). Roblox Instances use shared read-only metatables for method dispatch. pointer lives at a fixed offset in each value's header:
// Table struct (simplified)
typedef struct Table {
GCObject header;
uint8_t tmcache; // tag method cache bits
uint8_t readonly; // frozen flag
uint8_t safeenv;
uint8_t lsizenode; // log2(hash part size)
int sizearray; // array part length
TValue* array; // array part pointer
LuaNode* node; // hash part pointer
Table* metatable; // ← this is what getrawmetatable reads
} Table;
// Udata struct (userdata, e.g., Instances)
typedef struct Udata {
GCObject header;
uint8_t tag;
int len; // userdata size
Table* metatable; // ← same field for userdata
} Udata;
getrawmetatable reads obj->metatable directly, bypassing the VM's luaT_objtypename guard that checks __metatable.Shared metatable
All Roblox Instances share a single global metatableMetatableA table attached to another table (or userdata) that defines operator overloading via metamethods (__index, __newindex, __call, etc.). Roblox Instances use shared read-only metatables for method dispatch.. This metatable contains
__index, __newindex, __namecall, __tostring, and __eq. Modifying it (after setreadonly(mt, false)) affects every InstanceInstanceThe base class for all Roblox objects (Parts, Models, Scripts, GUIs, etc.). Instances form a tree hierarchy (the DataModel). In Luau, they appear as userdata with shared metatables. in the game. The __metatable field is set to "The metatable is locked" to prevent normal getmetatable() access.Usage
Unlock and modify a metatable
local mt = getrawmetatable(game)
"cc">-- Make the metatable writable
setreadonly(mt, false)
"cc">-- Now you can replace metamethods
mt.__index = function(self, key)
print("Property accessed:", key)
return rawget(mt, key)
endParameters
object any The object to retrieve the raw metatable from.
Returns
table The unguarded metatable of the provided object.