Rules
Look up any error shot check prints: what causes it, and how to fix it.
shot check prints one line per error: <project>/<file>:<line>:<column> <message>. The column is missing when the error is about a whole line. Each message below is written as shot check prints it, with a note beside it when the message alone doesn't say what to do. Names in the messages are examples.
Parse errors: the ShotScript layer
These come from reading the ShotScript layer of a file: its declaration, its members and the keywords around them.
File level
a file can only declare one class, module or funcone declaration per file; move the rest outa file can only have one types linea file can only have one rootdoca doc above a func counts as its rootdocdoc must sit above a member inside a class or modulea doc below the declarationdoc { is never closed with }(alsorootdoc {)@server goes on the first line of the file@client needs enabled or disabled after it: @client enabledimport needs: import Name[, Name] from path, or import * from pathpublic type needs: public type Name = type(alsointernal type)class Shape: expected = { after the nameclass Shape = { ... }, with the=
Class bodies
class Shape is never closed with }class Shape: expected public, internal, override, constructor or doc, got 'private'a class method has no function keyword: public Name(...) ... endpublic function Get()written the Luau wayclass Shape: a method starts with public, internal or override and has no function keyword: public Name(...) ... endclass Shape: a helper only this file uses goes above the class, as a local functionmodule Bank: module members take no public (a module is all public; a helper only this file uses is a local function above it): function Name(...) ... endmodule Bank: a local goes above the module, not inside itclass Shape: extends needs a class nameclass Shape: implements needs an interface namerequired is for static functions: public required static Name(...) (the game must call it somewhere)static is for functions only. A field with a value is already a class property: public Speed : type = valueany static field; writepublic Speed : number = 10Speed: a class property needs a type and a value: Speed : type = valuepublic Speed : number =(nothing after the=)override static: a static function belongs to its class and can't be overridden
Module bodies
module Bank is never closed with }module Bank: property Count needs a value (Count : type = value)module Bank: expected a property (Name : type = value), function or doc, got 'constructor'modules have no constructors
Functions (methods, constructors, module functions, funcs)
public Damage is never closed with endpublic: expected a nameDamage: expected ( after the nameDamage: ( is never closed with )Box: < is never closed with >constructor new: a constructor always returns Shape, so it takes no return type (drop : Shape)
Interface bodies (see Interfaces)
interface Payer is never closed with }interface Payer: a member is only its signature, Name(params) : Return, or a field, Name : Type (all public, no body, no public)interface Payer: an interface has no generics
match (see Match)
match: each case starts its line with its value and then, like "Pickup" then (several: "Pickup", "Shop" then)match needs at least one case, like "Pickup" then ...match is never closed with endmatch: a case after else is never reached (else goes last)match: only one else
uses (see Uses)
uses Wallet Utils: give folders from the project root, like uses Wallet, Market, Utils/Signal (or uses nothing, uses everything)a file can only have one uses line
split module / diffsource func
split module Market is never closed with }split module Market has no Client -> line(or Server)split module Market: Client is given twicesplit module Market: Client -> needs a pathsplit module Market: expected Client -> path or Server -> path, got 'Other'
After a broken line in a class or module body, the parser stays quiet until the next real member, so one unclosed ( is one error.
Project errors: Types lines and imports
These come from following a file's types line and its folder's imports to the files they name.
The types line
types path must start with script or @shot: Typestypes file not found: script.Parent.Typse
Imports
import: nothing at @shot.Prizsno file there; a folder without an entry point is imported through one of its filesimport: @shot.Wallet has no public type Reasnnot there, or not written yetimport: Slot is internal to @shot.Wallet (class types and internal types stay in their folder)
ShotScript's rules
The file reads fine but breaks one of ShotScript's rules. They are grouped by topic, most with the doc that explains the rule.
Files
Wallet.shot declares Walet: the name must match the filedeclares nothing yet: a .shot file needs one class, module or func, or @client / @server on its first line to be a scriptneeds a types line (types script.Parent.Types)a Types file holds imports and types only, not a classRunner.shot is a @client script: a script runs and returns nothing, so it can't declare a classShapeClass is the generated type of class Shape: pick another nameimport only works in a Types file: move it to this folder's Types.shot (every file of the folder sees what it imports)
Docs (see Doc comments)
a doc can only have one section Rules`Bank.Giev` in this doc: Bank has no Giev (renamed or removed?)`Nope.Thing` in this doc: Nope names nothing in this project, Roblox or Luau (renamed or removed?)`Nope/MarketClient.Open` in this doc: no folder Nope (renamed or removed?)`@shot.Wallet.Nope` in this doc: nothing at @shot.Wallet.Nope (renamed or removed?)`self.Speed` in this doc: self only means something in a class's docs (renamed or removed?)
Requires and sides (see Server and client; use follows the same rules, see Files, USE)
client code requires server MarketServer (Market/MarketServer.shot)both code requires server MarketServer (Market/MarketServer.shot)make the requiring file server-onlyClient is a @client script (Init/Client.shot): a script can't be requiredclient code uses Market.Serverthe nil half of a split module
Classes (see Classes)
internal Shape._hp is used outside Shapesinternalis folder-wideinit() only works inside a classmodule only works inside a module: in class Shape use self (Shape.Name for statics and class properties)parameter factor of Scale has no type: write factor : Type (untyped, it is any and mistakes with it go unnoticed)class property Marks is one table shared by every object, and Mark changes it: give each object its own in the constructor (self.Marks = {})a class property's table is shared; one that is only read is fineinternal Shape.Tick is used outside Shapeschecked on the receiver's type when it is known (pen : Pen,use,require,self), by name otherwisemodule is a module's own name in ShotScript: rename this onea local or parameter namedmoduleIsDead already exists in Shape: mark it overrideoverride Fly: no Fly in Shape or aboveoverride Fly: class Bird extends nothingoverride IsDead is (number) -> boolean but Shape.IsDead is () -> booleanparameter and return types must matchextends Shap: no class with that nameextends Shape: it lives in another folder, so require it first (local Shape = require(...))
Interfaces (see Interfaces)
Vault implements Payer but has no Worth() : numberWallet implements Payer, but a member doesn't fit it: Property 'Pay' is not compatible. ...found by Luau's type checkerChest implements Priced but its PriceFor is internal: what an interface promises is publicChest implements Priced but its PriceFor is static, not a method PriceFor(userId : number) : numberimplements Priced: no interface called Priced (shot find Priced)implements Priced: Priced is not visible here; import it in this folder's Types.shot: import Priced from @shot.Marketuse Payer: an interface is only a type, with nothing to require. ...interface Payer can't be its folder's entry file: an interface has no module behind it. ...
match (see Match)
match on Reason has no case for "Prize" (added at Wallet/Types.shot:2): add the case, or an elsematch case "Shpo" is not one of the values it matches on: "Gift" | "Pickup" | "Shop"match on a string that is not a union of string values: shot can't tell whether its cases cover everything, so give it an else
required (see Modules, REQUIRED FUNCTIONS)
required Bank.Start is never called: the game runs without it
uses (see Uses)
Market may use Wallet and Utils (Market/Types.shot:1), not Prizes: add Prizes there (calling it and hearing its declared events both count as using it)Wallet and Market would use each other (Market/Types.shot:1 lets Market use Wallet): drop one direction, e.g. turn a call into an event the caller declares in its Types.shot and the other imports, which reverses that linkuses goes in the system's Types.shot, where it covers every file of the folder
events (see Events)
CoinsGiven is Wallet's event (Wallet/Types.shot:3): only files in Wallet publish itCoinsGiven is published only by Wallet, Shop (Wallet/Types.shot:1), and this publish is from Prizes: its listeners count on those publishers alone, so publish through one of them (call the function of theirs that publishes it), or, if Prizes is meant to publish it too, add it to the list: published by Wallet, Shop, Prizes at Wallet/Types.shot:1event CoinsGiven: published by names Shpo, which is no system of this project (nearest: Shop); published by lists systems, the project's top folders, like published by WalletEventBus.Subscribe("CoinsGiven", ...) skips the declared payload of CoinsGiven(player : Player, amount : number, reason : Reason) (Wallet/Types.shot:3): write CoinsGiven. Subscribe(function(player : Player, amount : number, reason : Reason) ... end) event CoinsGiven is already declared at Prizes/Types.shot:3: an event's name is its EventBus topic, so each name is declared oncenote: event CoinsGiven is never heard; published at Wallet/Bank.shot:8a note, not an error
owned fields (see Owned fields)
Purse.Coins belongs to Wallet: change it with WalletServer.Grant instead (Grant also tells the player how many coins they have; a write to Coins does not)owns Purse.Coin: Purse has no field Coin (nearest: Coins)owns Purse.Gems via WalletServer.Grnt: WalletServer has no function or method Grnt (nearest: Grant)owns Chest.Gold: Chest is Prizes's (Prizes/Chest.shot), and a system owns only fields of its own classes and modules: move this line to Prizes/Types.shotowns Purse.Add: Add is a method of Purse, not a field; owns guards a field (Purse has Coins and Gems), and the method goes after viaowns goes in the system's Types.shot, the system whose class or module has the field: move this line there
start order (see Start order)
Market.Start() runs before Wallet.Start() (line 8), but Market.Start must run after it (Market/Market.shot:12: after Wallet.Start {it prices gems with the rates Wallet loads}): move this line below line 8; or, to keep this order, make Market.Start do that without Wallet.Start (when it is first needed, not at start), then drop after Wallet.Start there; or if Market no longer needs that order, drop after Wallet.Start thereafter Walet.Start {it prices gems with the rates Wallet loads}: no script calls Walet.Start() (nearest: Wallet.Start): write the name as Init/Server.shot calls itafter Market.Start and Market/Market. shot:12's after Wallet.Start {it prices gems with the rates Wallet loads} can't both hold: each wants its Start first. Keep the one that is still true and drop the other a comma goes between two names: after Wallet.Start, Bank.Startno script calls Start of Market/Market.shot, so its after can't be checked: call it from the script that starts the game (Init/Server.shot), or drop the clause
remotes (see Remotes)
Board.ByUser : {[number] : number} goes through WalletSnapshot: Roblox sends number keys as strings ("1002"), so a lookup by number on the other side reads nil; key it by tostring(id) ({[string] : number})lists that can hold nil, mixed tables, functions and class instances in a payload, a payload list filled by index inside an if, and Fire calls or handlers that don't match the signature: the whole list is in Remotes
split and diffsource targets
split Market: nothing at Client -> script.Parent.MarketCliendiffsource UniqueIdentifier: Client -> script.Parent.UIDClient is not a funcdiffsource UniqueIdentifier: Client -> UIDServer is a server funcdiffsource UniqueIdentifier: Client is () -> string but Server is () -> number
Luau errors
Everything else comes from Luau's type checker (Studio's, the old solver), mapped back to the .shot line. The message starts with its kind: TypeError, SyntaxError, or a lint name. These are the usual ones.
Names, types and requires
TypeError: Unknown global 'Bank'; consider assigning to it firstthe name is used above its declaration (Modules), or a module function is called withoutmodule.TypeError: Unknown type 'Pos'not in the folder's types: define it inTypes.shotor import it (Types)TypeError: Unknown type 'Wallet'; it is declared in Wallet: add import Wallet from @shot.Wallet to Market/Types.shota public type of another system: the error names the import line and the Types file it goes inTypeError: Unknown require: game/ReplicatedStorage/Shot/Prizesa folder without an entry point; require one of its filesSyntaxError: Invalid attribute '@shot'@shotfollowed by something that isn't a path (@shotalone, or@shot.); write@shot.System.File(Files)
Type checker traps (see Luau tips)
TypeError: Key 'Tool' not found in table '{ ["Food" | "Tool"]: number }'TypeError: Expected this to be '"Food" | "Tool"', but got 'string'TypeError: Key 'Id' is missing from 'true' in the type 'Def | true'TypeError: Cannot call a value of type {Def} in union: {Def} | {| |}
Classes (see Classes)
DuplicateLocal: Function parameter 'self' already defineda method parameter named self (Classes, PARAMETERS)TypeError: Cannot cast 'string' into 'number' because the types are unrelateda class property's default doesn't fit its type (Classes, CLASS PROPERTIES)
