isreadonly
Returns whether a table is frozen (read-only).
function isreadonly(t: table): booleanSynopsis
How it works
Checks the
readonly flag on the table header. In Luau, tables have an internal boolean flag that prevents writes when set. This flag is separate from metatablesMetatableA 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. — the __newindex 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.). is never consulted because the VM rejects the write at the table-access level before metamethod dispatch.VM internals
The flag lives in the
Table struct header:
typedef struct Table {
GCObject header;
uint8_t tmcache; // tag method cache
uint8_t readonly; // ← this flag (0 = mutable, 1 = frozen)
uint8_t safeenv;
// ...
} Table;
When readonly == 1, the VM’s SETTABLEKS, SETTABLEN, and SETTABLE opcodes check this field first and throw "Attempt to modify a readonly table" before any 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.). lookup. The freeze check happens at the C level before __newindex is even considered. table.freeze() and setreadonly(t, true) both set this byte.Usage
Check table mutability
local t = table.freeze({})
print(isreadonly(t)) "cc">--> trueParameters
t table The table to check.
Returns
boolean true if the table is frozen.