• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • 2026 staff recruitment is open! Check it out and consider applying!

C++ crashlog luaItemGetUniqueId

Darius93

Active Member
Joined
Oct 16, 2022
Messages
88
Reaction score
27
Hello, it’s me again :D
I’ve got a problem because early this morning my server crashed due to the luaItemGetUniqueId function.
crashlog: https://pastebin.com/raw/ZdueEn7C

Here are the scripts that contain this function:
Code:
data/npc/scripts/handlarz.lua:        playerMarket[cid] = { itemId = handItem:ge                                      tId(), itemUid = handItem:getUniqueId() }
data/actions/scripts/other/partyhat.lua:        if headSlotItem == nil or item.u                                      id ~= headSlotItem:getUniqueId() then
data/actions/scripts/tools/fishing.lua:    if not leftHand or leftHand:getUnique                                      Id() ~= item:getUniqueId() then
data/movements/scripts/tiles.lua:                       local depotItems = playe                                      r:getDepotLocker(getDepotId(depotItem:getUniqueId()), true):getItemHoldingCount(                                      )
data/movements/scripts/closingdoor.lua:         if tileItem and tileItem:getUniq                                      ueId() ~= item.uid and tileItem:getType():isMovable() then
data/lib/compat/compat.lua:                     return methods.getUniqueId(self)
data/lib/compat/compat.lua:                     t.uid = thing:getUniqueId()
data/lib/compat/compat.lua:     return item:getUniqueId()
data/lib/compat/compat.lua:             return item:getUniqueId()
data/lib/compat/compat.lua:             return item:getUniqueId()
data/spells/scripts/support/disintegrate rune.lua:                             i                                      f item:getType():isMovable() and item:getUniqueId() > 65535 and item:getActionId


I edited fishing and here’s what I have:
LUA:
function onUse(player, item, fromPosition, target, toPosition, isHotkey)

    -- sprawdzenie czy gracz w obszarze
    if not isInFishingArea(player:getPosition()) then
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz znajdowac sie w poblizu Rybaka.")
        return true
    end

    -- sprawdzenie czy wedka jest w lewej rece
    local leftHand = player:getSlotItem(CONST_SLOT_LEFT)
    if not leftHand or leftHand:getUniqueId() ~= item:getUniqueId() then
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
        return true
    end

And here’s the one from the merchant:

LUA:
 -- dodawanie przedmiotu
    if text == "dodaj przedmiot" or text == "dodaj" then
        if getPlayerMarketCount(player) >= 5 then
        say(cid, "Mozesz miec maksymalnie 5 aktywnych ofert na rynku.")
        reset(cid); return true
    end
        local handItem = player:getSlotItem(CONST_SLOT_AMMO)
        if not handItem then
            say(cid, "Musisz trzymac przedmiot w slocie na amunicje.")
            reset(cid); return true
        end
        npcHandler.topic[cid] = TOPIC.ADD_CURRENCY
        playerMarket[cid] = { itemId = handItem:getId(), itemUid = handItem:getUniqueId() }
       -- say(cid, "Chcesz dodac ten przedmiot na aukcje za gp czy za premium points? [gp] [premium points]")
        local msgs = {"Aby dodac przedmiot, musisz miec go w slocie na amunicje. Jesli chcesz dodac plecak, pamietaj, ze straci on swoja zawartosc..","Chcesz dodac ten przedmiot na aukcje za gp czy za premium points? [gp] [premium points]"}
npcHandler:doNPCTalkALot(msgs, 5000, cid)
        return true
    end

    if npcHandler.topic[cid] == TOPIC.ADD_CURRENCY then
        if text == "gp" or text == "gold" then
            playerMarket[cid].currency = "gold"
            npcHandler.topic[cid] = TOPIC.ADD_PRICE
            say(cid, "Podaj cene w gp.")
            return true
        elseif text == "premium" or text == "premium points" then
            playerMarket[cid].currency = "points"
            npcHandler.topic[cid] = TOPIC.ADD_PRICE
            say(cid, "Podaj cene w premium points.")
            return true
        else
            say(cid, "Wybierz gp albo premium points. [gp] [premium points]")
            return true
        end
    end

    if npcHandler.topic[cid] == TOPIC.ADD_PRICE then
        local price = tonumber(text)
        if not price or price <= 0 then
            say(cid, "Podaj poprawna liczbe wieksza od 0.")
            return true
        end

        local data = playerMarket[cid]
        if not data then
            say(cid, "Cos poszlo nie tak. Sprobuj ponownie.")
            reset(cid); return true
        end

        data.price = price
        npcHandler.topic[cid] = TOPIC.CONFIRM

        local handItem = player:getSlotItem(CONST_SLOT_AMMO)
        if not handItem then
            say(cid, "Nie trzymasz zadnego przedmiotu w slocie na amunicje.")
            reset(cid); return true
        end

        say(cid, "Chcesz dodac " .. handItem:getCount() .."x " .. handItem:getName() .. " za " .. formatCurrency(price) .. " " .. data.currency .. "? [tak] [nie]")
        return true
    end

    if npcHandler.topic[cid] == TOPIC.CONFIRM then
        if isNo(text) then
            say(cid, "Okej, wroc innym razem..")
            reset(cid); return true
        elseif isYes(text) then
            local data = playerMarket[cid]
            if not data then
                say(cid, "Cos poszlo nie tak. Sprobuj ponownie.")
                reset(cid); return true
            end

            local handItem = player:getSlotItem(CONST_SLOT_AMMO)
            if not handItem or handItem:getId() ~= data.itemId then
                say(cid, "Nie trzymasz juz tego samego przedmiotu w slocie na amunicje.")
                reset(cid); return true
            end

            local success, msg = doAddMarketItem(player, handItem, data.price, data.currency)
            say(cid, msg)
            reset(cid)
            return true
        else
            say(cid, "Odpowiedz tak albo nie. [tak] [nie]")
            return true
        end
    end

    return true
end


And I’ve got a problem because I can’t figure out why this happened — I’ll add that it’s the first time it’s occurred in a month.
It happened early in the morning — I checked if any player logged in during that time frame, but no one did.

I have a feeling that it just triggered by itself.
Can someone explain to me why this happened? :D
 
Solution
Hey there! 👋

I've seen this crash before on my server too - it's a classic race condition with item UIDs. Let me break down what's happening and how to fix it.

What's causing the crash:

The problem is that you're storing item UIDs in the playerMarket[cid] table, and between the time you store them and when you try to use them, the item can become invalid. This can happen when:
  • Player logs out mid-conversation with NPC
  • Item gets moved/removed
  • Server does a cleanup at night (which explains why it crashed at 5 AM with no players online!)
  • The item despawns or gets invalidated
Basically, the NPC is holding onto a "dead" reference to an item that no longer exists.

The Fix:

1. First, let's...

Hey there! 👋

I've seen this crash before on my server too - it's a classic race condition with item UIDs. Let me break down what's happening and how to fix it.

What's causing the crash:

The problem is that you're storing item UIDs in the playerMarket[cid] table, and between the time you store them and when you try to use them, the item can become invalid. This can happen when:
  • Player logs out mid-conversation with NPC
  • Item gets moved/removed
  • Server does a cleanup at night (which explains why it crashed at 5 AM with no players online!)
  • The item despawns or gets invalidated
Basically, the NPC is holding onto a "dead" reference to an item that no longer exists.

The Fix:

1. First, let's fix your fishing script:

The issue here is you're comparing UIDs when you should just compare item IDs.
Replace this:

LUA:
local leftHand = player:getSlotItem(CONST_SLOT_LEFT)
if not leftHand or leftHand:getUniqueId() ~= item:getUniqueId() then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
    return true
end

With this:
LUA:
local leftHand = player:getSlotItem(CONST_SLOT_LEFT)
if not leftHand then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
    return true
end

-- Compare IDs instead of UIDs
if leftHand:getId() ~= item:getId() then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
    return true
end

2. Now for the merchant script (this is the main culprit):

The big mistake is storing itemUid in the playerMarket table. Never store UIDs for later use - they can become invalid!
Add this helper function at the top of your handlarz.lua:


lua
LUA:
local function isItemValid(item)
    return item and item:getType() and item:getId() > 0
end


Then change this part:


lua
LUA:
-- OLD (BAD):
playerMarket[cid] = { itemId = handItem:getId(), itemUid = handItem:getUniqueId() }

-- NEW (GOOD):
playerMarket[cid] = {
    itemId = handItem:getId(),
    itemCount = handItem:getCount()
    -- NO itemUid!
}

And update all your validation checks to use the helper:


lua
LUA:
-- Instead of:
if not handItem then

-- Use:
if not isItemValid(handItem) then
    say(cid, "Nie trzymasz zadnego przedmiotu w slocie na amunicje.")
    reset(cid)
    return true
end


3. Make sure your reset() function clears everything:



lua
LUA:
function reset(cid)
    npcHandler.topic[cid] = nil
    playerMarket[cid] = nil  -- Important! Clear the stored data
end

4. Add global protection (optional but recommended):

In your data/lib/compat/compat.lua, add this safety wrapper:


lua
LUA:
-- Add this near the other Item methods
local _getUniqueId = Item.getUniqueId
function Item:getUniqueId()
    if not self or not self:getType() then
        return 0
    end
    return _getUniqueId(self)
end


This will catch any other scripts that might have the same issue.

Why it crashed at 5 AM with no players online:

This is actually the smoking gun! 🔍

What probably happened:
  1. A player started talking to the merchant yesterday
  2. They put an item in the ammo slot and started the process
  3. They logged out or got disconnected mid-conversation
  4. The NPC kept the conversation state in memory with that itemUid stored
  5. At 5 AM, something triggered a cleanup or the NPC tried to timeout old conversations
  6. It tried to access handItem:getUniqueId() on an item that no longer exists
  7. BOOM 💥 Crash

Full corrected merchant script section:

Here's the complete fixed version of your "dodaj przedmiot" section:


lua
LUA:
-- Helper function at the top
local function isItemValid(item)
    return item and item:getType() and item:getId() > 0
end

-- dodawanie przedmiotu
if text == "dodaj przedmiot" or text == "dodaj" then
    if getPlayerMarketCount(player) >= 5 then
        say(cid, "Mozesz miec maksymalnie 5 aktywnych ofert na rynku.")
        reset(cid)
        return true
    end
    
    local handItem = player:getSlotItem(CONST_SLOT_AMMO)
    if not isItemValid(handItem) then
        say(cid, "Musisz trzymac przedmiot w slocie na amunicje.")
        reset(cid)
        return true
    end
    
    npcHandler.topic[cid] = TOPIC.ADD_CURRENCY
    playerMarket[cid] = {
        itemId = handItem:getId(),
        itemCount = handItem:getCount()
        -- Don't store UID!
    }
    
    local msgs = {
        "Aby dodac przedmiot, musisz miec go w slocie na amunicje. Jesli chcesz dodac plecak, pamietaj, ze straci on swoja zawartosc..",
        "Chcesz dodac ten przedmiot na aukcje za gp czy za premium points? [gp] [premium points]"
    }
    npcHandler:doNPCTalkALot(msgs, 5000, cid)
    return true
end

if npcHandler.topic[cid] == TOPIC.ADD_PRICE then
    local price = tonumber(text)
    if not price or price <= 0 then
        say(cid, "Podaj poprawna liczbe wieksza od 0.")
        return true
    end

    local data = playerMarket[cid]
    if not data then
        say(cid, "Cos poszlo nie tak. Sprobuj ponownie.")
        reset(cid)
        return true
    end

    data.price = price
    npcHandler.topic[cid] = TOPIC.CONFIRM

    local handItem = player:getSlotItem(CONST_SLOT_AMMO)
    if not isItemValid(handItem) then
        say(cid, "Nie trzymasz zadnego przedmiotu w slocie na amunicje.")
        reset(cid)
        return true
    end

    -- Verify item hasn't changed
    if handItem:getId() ~= data.itemId then
        say(cid, "Przedmiot sie zmienil. Sprobuj ponownie.")
        reset(cid)
        return true
    end

    say(cid, "Chcesz dodac " .. handItem:getCount() .."x " .. handItem:getName() .. " za " .. formatCurrency(price) .. " " .. data.currency .. "? [tak] [nie]")
    return true
end

if npcHandler.topic[cid] == TOPIC.CONFIRM then
    if isNo(text) then
        say(cid, "Okej, wroc innym razem..")
        reset(cid)
        return true
    elseif isYes(text) then
        local data = playerMarket[cid]
        if not data then
            say(cid, "Cos poszlo nie tak. Sprobuj ponownie.")
            reset(cid)
            return true
        end

        local handItem = player:getSlotItem(CONST_SLOT_AMMO)
        if not isItemValid(handItem) then
            say(cid, "Nie trzymasz przedmiotu w slocie na amunicje.")
            reset(cid)
            return true
        end
        
        -- Double-check item matches
        if handItem:getId() ~= data.itemId then
            say(cid, "Nie trzymasz juz tego samego przedmiotu w slocie na amunicje.")
            reset(cid)
            return true
        end

        local success, msg = doAddMarketItem(player, handItem, data.price, data.currency)
        say(cid, msg)
        reset(cid)
        return true
    else
        say(cid, "Odpowiedz tak albo nie. [tak] [nie]")
        return true
    end
end


TL;DR - Quick fix checklist:

✅ Don't store item UIDs - store only IDs
✅ Always validate items before using them
✅ Use isItemValid() helper function
✅ Compare items by ID, not UID
✅ Clear NPC conversation data properly


After making these changes, restart your server and the crashes should stop. I had the same issue on my 7.4 server and this fixed it completely - haven't had a crash in 3 months now! 😊
Let me know if you need help implementing this or if you get any errors!

Cheers! 🍻



EDIT: Also check your other scripts that use getUniqueId() - you might have similar issues in:
  • data/movements/scripts/tiles.lua
  • data/movements/scripts/closingdoor.lua
  • data/actions/scripts/other/partyhat.lua
Same fix applies - validate the item exists before calling any methods on it!
 
Solution
Hey there! 👋

I've seen this crash before on my server too - it's a classic race condition with item UIDs. Let me break down what's happening and how to fix it.

What's causing the crash:

The problem is that you're storing item UIDs in the playerMarket[cid] table, and between the time you store them and when you try to use them, the item can become invalid. This can happen when:
  • Player logs out mid-conversation with NPC
  • Item gets moved/removed
  • Server does a cleanup at night (which explains why it crashed at 5 AM with no players online!)
  • The item despawns or gets invalidated
Basically, the NPC is holding onto a "dead" reference to an item that no longer exists.

The Fix:

1. First, let's fix your fishing script:

The issue here is you're comparing UIDs when you should just compare item IDs.
Replace this:

LUA:
local leftHand = player:getSlotItem(CONST_SLOT_LEFT)
if not leftHand or leftHand:getUniqueId() ~= item:getUniqueId() then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
    return true
end

With this:
LUA:
local leftHand = player:getSlotItem(CONST_SLOT_LEFT)
if not leftHand then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
    return true
end

-- Compare IDs instead of UIDs
if leftHand:getId() ~= item:getId() then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Aby lowic ryby, musisz trzymac wedke w lewej rece.")
    return true
end

2. Now for the merchant script (this is the main culprit):

The big mistake is storing itemUid in the playerMarket table. Never store UIDs for later use - they can become invalid!
Add this helper function at the top of your handlarz.lua:


lua
LUA:
local function isItemValid(item)
    return item and item:getType() and item:getId() > 0
end


Then change this part:


lua
LUA:
-- OLD (BAD):
playerMarket[cid] = { itemId = handItem:getId(), itemUid = handItem:getUniqueId() }

-- NEW (GOOD):
playerMarket[cid] = {
    itemId = handItem:getId(),
    itemCount = handItem:getCount()
    -- NO itemUid!
}

And update all your validation checks to use the helper:


lua
LUA:
-- Instead of:
if not handItem then

-- Use:
if not isItemValid(handItem) then
    say(cid, "Nie trzymasz zadnego przedmiotu w slocie na amunicje.")
    reset(cid)
    return true
end


3. Make sure your reset() function clears everything:



lua
LUA:
function reset(cid)
    npcHandler.topic[cid] = nil
    playerMarket[cid] = nil  -- Important! Clear the stored data
end

4. Add global protection (optional but recommended):

In your data/lib/compat/compat.lua, add this safety wrapper:


lua
LUA:
-- Add this near the other Item methods
local _getUniqueId = Item.getUniqueId
function Item:getUniqueId()
    if not self or not self:getType() then
        return 0
    end
    return _getUniqueId(self)
end


This will catch any other scripts that might have the same issue.

Why it crashed at 5 AM with no players online:

This is actually the smoking gun! 🔍

What probably happened:
  1. A player started talking to the merchant yesterday
  2. They put an item in the ammo slot and started the process
  3. They logged out or got disconnected mid-conversation
  4. The NPC kept the conversation state in memory with that itemUid stored
  5. At 5 AM, something triggered a cleanup or the NPC tried to timeout old conversations
  6. It tried to access handItem:getUniqueId() on an item that no longer exists
  7. BOOM 💥 Crash

Full corrected merchant script section:

Here's the complete fixed version of your "dodaj przedmiot" section:


lua
LUA:
-- Helper function at the top
local function isItemValid(item)
    return item and item:getType() and item:getId() > 0
end

-- dodawanie przedmiotu
if text == "dodaj przedmiot" or text == "dodaj" then
    if getPlayerMarketCount(player) >= 5 then
        say(cid, "Mozesz miec maksymalnie 5 aktywnych ofert na rynku.")
        reset(cid)
        return true
    end
   
    local handItem = player:getSlotItem(CONST_SLOT_AMMO)
    if not isItemValid(handItem) then
        say(cid, "Musisz trzymac przedmiot w slocie na amunicje.")
        reset(cid)
        return true
    end
   
    npcHandler.topic[cid] = TOPIC.ADD_CURRENCY
    playerMarket[cid] = {
        itemId = handItem:getId(),
        itemCount = handItem:getCount()
        -- Don't store UID!
    }
   
    local msgs = {
        "Aby dodac przedmiot, musisz miec go w slocie na amunicje. Jesli chcesz dodac plecak, pamietaj, ze straci on swoja zawartosc..",
        "Chcesz dodac ten przedmiot na aukcje za gp czy za premium points? [gp] [premium points]"
    }
    npcHandler:doNPCTalkALot(msgs, 5000, cid)
    return true
end

if npcHandler.topic[cid] == TOPIC.ADD_PRICE then
    local price = tonumber(text)
    if not price or price <= 0 then
        say(cid, "Podaj poprawna liczbe wieksza od 0.")
        return true
    end

    local data = playerMarket[cid]
    if not data then
        say(cid, "Cos poszlo nie tak. Sprobuj ponownie.")
        reset(cid)
        return true
    end

    data.price = price
    npcHandler.topic[cid] = TOPIC.CONFIRM

    local handItem = player:getSlotItem(CONST_SLOT_AMMO)
    if not isItemValid(handItem) then
        say(cid, "Nie trzymasz zadnego przedmiotu w slocie na amunicje.")
        reset(cid)
        return true
    end

    -- Verify item hasn't changed
    if handItem:getId() ~= data.itemId then
        say(cid, "Przedmiot sie zmienil. Sprobuj ponownie.")
        reset(cid)
        return true
    end

    say(cid, "Chcesz dodac " .. handItem:getCount() .."x " .. handItem:getName() .. " za " .. formatCurrency(price) .. " " .. data.currency .. "? [tak] [nie]")
    return true
end

if npcHandler.topic[cid] == TOPIC.CONFIRM then
    if isNo(text) then
        say(cid, "Okej, wroc innym razem..")
        reset(cid)
        return true
    elseif isYes(text) then
        local data = playerMarket[cid]
        if not data then
            say(cid, "Cos poszlo nie tak. Sprobuj ponownie.")
            reset(cid)
            return true
        end

        local handItem = player:getSlotItem(CONST_SLOT_AMMO)
        if not isItemValid(handItem) then
            say(cid, "Nie trzymasz przedmiotu w slocie na amunicje.")
            reset(cid)
            return true
        end
       
        -- Double-check item matches
        if handItem:getId() ~= data.itemId then
            say(cid, "Nie trzymasz juz tego samego przedmiotu w slocie na amunicje.")
            reset(cid)
            return true
        end

        local success, msg = doAddMarketItem(player, handItem, data.price, data.currency)
        say(cid, msg)
        reset(cid)
        return true
    else
        say(cid, "Odpowiedz tak albo nie. [tak] [nie]")
        return true
    end
end


TL;DR - Quick fix checklist:

✅ Don't store item UIDs - store only IDs
✅ Always validate items before using them
✅ Use isItemValid() helper function
✅ Compare items by ID, not UID
✅ Clear NPC conversation data properly


After making these changes, restart your server and the crashes should stop. I had the same issue on my 7.4 server and this fixed it completely - haven't had a crash in 3 months now! 😊
Let me know if you need help implementing this or if you get any errors!

Cheers! 🍻



EDIT: Also check your other scripts that use getUniqueId() - you might have similar issues in:
  • data/movements/scripts/tiles.lua
  • data/movements/scripts/closingdoor.lua
  • data/actions/scripts/other/partyhat.lua
Same fix applies - validate the item exists before calling any methods on it!
Thank you, good person!


I’m really glad there are such helpful people like you who are willing to share their knowledge and experience!


I think I’ll have no problem adding what you wrote to me ;)


Once again, big thanks! 🙏
 
Back
Top