WireType
UpdatedThe rule behind this error is on the Wire types page.
A remote carries data across the network. A parameter typed as a function, a thread, a Future, or a Signal cannot be serialized, so the declaration is an error:
remote Ping(cb: () -> ()) from client -- remote `Ping`: parameter `cb` has type `() -> ()`, which is a function type; a remote carries only data
Send an id, a name, or a plain table, and keep the callback on the side that owns it.
How a payload travels. The compiler reads a layout from the parameter types, and picks the encoding that sends fewer bytes. A payload goes in one buffer when a parameter packs smaller there: a number with a width attribute, a struct or a record, whose key names the buffer leaves out, or an array of numbers, booleans, or records, whose type tags it leaves out. Otherwise it goes as Roblox encodes a table, since a lone string, boolean, or 64-bit number gains nothing in a buffer. @wire(buffer) and @wire(table) on the remote choose for you.
struct Shot @f32 x: number @f32 y: number @u8 power: number end remote Fire(shot: Shot, @u16 id: number) from client -- a buffer: 11 bytes remote Chat(message: string) from client -- a table
A width attribute sets a number's size, @u8, @u16, @u32, @i8, @i16, @i32, @f32; a number without one takes 64 bits. A string or an array writes its length in one byte under 128. A value that does not fit its width raises at the fire: Heal: argument 1: 300 does not fit @u8. A struct, a record type, or an array packs field by field and item by item, down to any depth, and a struct comes back through its constructor, so a @skip field, which stays off the wire, takes its default. An Instance, a Player, and a Roblox datatype such as Vector3 or CFrame travel beside the buffer in the engine's own encoding. A map is not packed: @wire(buffer) reports one.
What the receiver checks. The other side may be anyone, so a packet is checked before the handler runs, whichever way it travelled: every value against its type and width, an Instance against its class, a datatype against its typeof, and every length against the bytes the packet holds. A packet that does not fit drops, and the handler never sees it; so does a packet with bytes or values past its layout. On the server @ratelimit counts a packet before it is read, so a flood costs no decoding.
@unreliable rides an UnreliableRemoteEvent, which drops a payload over 900 bytes: a string, an array, or a map on one reports, and so do fixed sizes that add up past the limit.
