CreateJob wrote the caller's skin table straight into ESX.Jobs while the row
got the encoded string. setJob then ran json.decode over a table and died with
"bad argument #1 to 'json.decode' (string expected, got table)". A restart
appeared to repair the job, because the grade came back from the database as a
string. Cache the same value that goes into the row.
A grade that already exists in the database is skipped for the insert, but it
was still written to ESX.Jobs. A second CreateJob call therefore replaced the
stored name, label and salary in memory while the row itself kept the old
values, and the two only agreed again after a restart. CreateJob now caches
just the grades it inserted.
Label and type of an existing job come from the database for the same reason.
The grade lookup compares strings, so passing grade "1" for an existing grade 1
no longer inserts a second row.
The jobs row was inserted unconditionally, so adding a grade to an existing
job hit a duplicate primary key and rolled the whole transaction back. The
guard above it only caught the case where there was nothing to add, and it
read ESX.Jobs, which does not list jobs that have no grades yet.
Both default skins spell the chin width key chin_13. skinchanger only
knows chin_1 through chin_4, so the value never reaches the ped and the
key is stored as junk in users.skin.
It also breaks the ped. SetFace reads every feature through
Normalise(weight, 10), which divides, so a missing chin_3 raises
"attempt to perform arithmetic on a nil value" at feature index 17.
Everything after that in ApplySkin is skipped: the remaining features,
the eye colour, the head overlays, the components and the props.
The column is varchar(22), which is a leftover from Steam identifiers.
esx_vehicleshop writes a player identifier into it, and on a
multicharacter server those are 46 characters long, so renting a vehicle
out fails.
The stock vehicle is deleted from cardealer_vehicles before the insert
runs, so the dealer loses the car and the customer never gets a rental
contract. Neither side is told anything, because the handler dies on the
insert.
esx_vehicleshop's own esx_vehicleshop.sql already declares varchar(60).
The column is varchar(40) but esx_billing writes an identifier into it, and
those are 46 characters once multicharacter is on, so the insert fails with
1406 and the handler dies before notifying either player. The other two
identifier columns in the same table are already varchar(60).
Setting an item to the count it already has sent a zero difference to
removeInventoryItem, which treats zero as an error and calls error(). That
unwinds out of the caller, so anything after the call was skipped.
Placeholder results go straight into gsub as the replacement string, so a %
in a player name either throws and kills the presence thread or silently
mangles the output. The "Unknown" fallback above it was unreachable because
the error() on the previous line always propagates.
RegisterCommand hands the callback xPlayer or false, so group, refreshitems
and fix threw from the server console instead of doing their work. The same
three lines still used the old showNotification argument list, which put a
number into title and made esx_notify throw, so players got no confirmation
either.
math.type only returns 'integer', 'float' or nil, so the 'uint' branch
comparing against 'int' never matched and threw whenever throw_error was set.
pressedInteractions was written on every interaction and read nowhere, so it
grew for the whole session and kept removed interactions reachable.
OnTime always built scheduledTimestamp from the date of the current tick, so
a tick that skipped the 23:59 minute compared it against 23:59 of the next
day. The run was dropped without a trace. Fall back to the previous day when
the scheduled time lands in the future.
setVehicleProperties passes props.color1 straight into SetVehicleColours when the
secondary colour comes from the palette. If the primary is a custom RGB colour,
the getter stored it as a table, so a table reaches a native that wants a paint
index and the call does nothing. The secondary colour is silently lost.
Any car sprayed with a custom primary and a palette secondary comes back from
storage with the wrong secondary colour.
Fall back to the vehicle's current primary when props.color1 is not a paint index.
The custom primary was already applied by the block above, so nothing is lost.
Measured in game on artifact 25770, reading properties off a car with a custom red
primary and palette secondary 12, then applying them to a second car:
before: color2 came back 0
after: color2 came back 12
The custom primary survives either way, mods and wheels are untouched.
xLib.name was "xLib", which is not a resource, so the import metatable fed it to LoadResourceFile and resolved nothing. It failed silently on Legacy and hard-errored on Enhanced (Resource 'xLib' not found). Point it at the real resource name.
xLib.isEnhanced() returns whether the game runs GTA V Enhanced (server: gamename convar, client: IsGameEnhancedVersion native). es_extended reads it once and requires OneSync Infinity on Legacy only, since Enhanced runs OneSync natively.