VINDICTA
Debug · Library
Bunni.fun
ChocoSploit
Cryptic
Potassium
Seliware
SirHurt
Solara
Velocity
Volcano
Volt
Wave
Xeno

debug.getproto

Returns the proto (inner function) at a given index of a function.

function debug.getproto(func: function | number, index: number, active: boolean?): function | {function}

Synopsis

How it works

Retrieves a nested function prototype (Proto.p[index]) from a Luau closureClosureA function value that captures its lexical environment. In Luau, closures come in two types: LClosure (Luau bytecode + Proto + upvalues) and CClosure (native C function pointer + upvalues).. Every function defined inside another function exists as a child proto. When active is true, returns all live closures that were instantiated from that proto (searching the GC), which may be multiple closures with different upvalueUpvalueA variable captured from an enclosing scope. When a function references a local variable from an outer function, that variable becomes an upvalue — stored in an UpVal struct that persists even after the outer function returns. bindings.

Proto tree — compilation model

The Luau compiler produces a tree of Proto objects mirroring the lexical nesting of functions:
-- Source:
local function outer()        -- Proto #0 (root)
  local function inner_a()    -- Proto #0.p[0]
    local function deep()     -- Proto #0.p[0].p[0]
    end
  end
  local function inner_b()    -- Proto #0.p[1]
  end
end
The Proto.p[] array stores pointers to child protos. The CLOSURE bytecodeBytecodeThe compiled binary representation of Luau source code. A sequence of 32-bit instructions (opcodes + operands) stored in a Proto's code[] array. Executed by the Luau VM interpreter. instruction (CLOSURE R(A), P(Bx)) instantiates a child proto into a live LClosure by binding upvaluesUpvalueA variable captured from an enclosing scope. When a function references a local variable from an outer function, that variable becomes an upvalue — stored in an UpVal struct that persists even after the outer function returns..

Active closures

When active=true, the executor walks the GC to find all live LClosure objects whose p pointer matches the target proto. Multiple closures can exist from the same proto if the parent was called multiple times — each call creates a new closureClosureA function value that captures its lexical environment. In Luau, closures come in two types: LClosure (Luau bytecode + Proto + upvalues) and CClosure (native C function pointer + upvalues). with different upvalueUpvalueA variable captured from an enclosing scope. When a function references a local variable from an outer function, that variable becomes an upvalue — stored in an UpVal struct that persists even after the outer function returns. bindings. This is how you find the "live" copy of an inner function with actual captured state.

Usage

Call an inner function
local function myFunction()
	local function proto()
		print("Hello, world!")
	end
end
local proto = debug.getproto(myFunction, 1, true)[1]
proto() "cc">--> Hello, world!

Parameters

func function | number
A Luau function or stack level.
index number
Index of the inner proto.
active boolean optional
If true, returns active closures instead.

Returns

function | {function} The proto function, or list of active closures.