AvatarItem command issue

Hello, I am having an issue where players are not able to give themselves accessories. The code works perfectly fine for me in studio, but sometimes, certain players are unable to use the command, giving them an unknown error has occurred.

I experimented with one player a while ago, and it was because they had a deleted T-Shirt on their avatar, but this user did not, and the AssetIds did not work. I am unsure how to debug this, and unsure if anyone else has had the same issue before, if so, I would love to know how to combat this issue, as it’s been an issue for a while now.

In this bug-report, the user was having issues and getting an unknown error occurred. I went and copied their avatar 1:1 and did not have their problem. I went into the same game as them with the same character as them and did NOT have the same issue either. Yet, he was still having it.

There are also NO errors in the output, server or client.

As you can see, I can use them perfectly fine. The user said the AssetId “13418414200” was the only one that worked out of the ones I tried in the picture.

I am unsure what is causing this issue, but it’s been a ongoing issue for a long while now.

The code for the command is below

local limits = {
	[8]  = {Enum.AccessoryType.Hat, 3},
	[41] = {Enum.AccessoryType.Hair, 1},
	[42] = {Enum.AccessoryType.Face, 1},
	[43] = {Enum.AccessoryType.Neck, 1},
	[44] = {Enum.AccessoryType.Shoulder, 1},
	[45] = {Enum.AccessoryType.Front, 1},
	[46] = {Enum.AccessoryType.Back, 1},
	[47] = {Enum.AccessoryType.Waist, 1}
}

local Shared = _G.Shared
local srv, gameProperties = Shared.GameServices, Shared.GameProperties

local NotificationService = _G.NotificationService
return {
	requiredLevel = gameProperties.TeamLevel,
	cmds = {
		"avataritem",
	},
	arguments = {
		"(username/userid)",
		"(asset id)"
	},
	desc = "Equip a accessory",
	examples = {
		"/avataritem me 2347823",
		"/avataritem me 2347823,123897"
	},
	
	automatic = true,
	options = {"me",{"all",gameProperties.AdminLevel},{"findplayer",gameProperties.ModeratorLevel}},
	params = {
		"admin:<sender>",
		"player:<player>:<true>",
		"assetid(s):<combine_extra>"
	},
	func = function(admin : Player, player : Player, aids) : boolean
		if typeof(player) ~= "Instance" then
			return false, "A valid player was not given"
		end
		
		aids = string.split(aids or "",",")
		if #aids < 1 then
			return false, "Did not list any items"
		end
		
		local char = player.Character
		if not char then
			return false, "Could not get character"
		end
		
		local function ApplyItem(aid, productInfo)
			local assetType = productInfo.AssetTypeId
			if (assetType >= 3 and assetType <= 5) or assetType == 9 or (assetType >= 19 and assetType <= 40) or assetType >= 48 then
				return false, "Cannot spawn item"
			end
			
			local limit = limits[assetType]
			local accessoryType = limit and limit[1] or Enum.AccessoryType.Unknown
			if limit then
				local total = char:GetAttribute(assetType) or 0
				if total + 1 > limit[2] then
					return false, string.format("Reached item limit %s/%s", total, limit[2])
				end
				char:SetAttribute(assetType, total + 1)
			end

			local asset
			local succ, err = pcall(function()
				asset = srv.insert:LoadAsset(aid)
			end)
			if not succ or not asset then
				return false, err or string.format("Failed to load item %s. It might be deleted or invalid.", aid)
			end
			
			if assetType == 11 then
				--/ Shirt
				local shirt = char:FindFirstChildOfClass("Shirt")
				if shirt then
					shirt:Destroy()
				end
				asset.Shirt.Parent = char
			elseif assetType == 12 then
				--/ Pants
				local pants = char:FindFirstChildOfClass("Pants")
				if pants then
					pants:Destroy()
				end
				asset.Pants.Parent = char
			elseif assetType == 18 then
				--/ Face
				local head = char:WaitForChild("Head")
				local faceDecal = head:FindFirstChildOfClass("Decal")
				if not faceDecal then
					return
				end
				faceDecal["Texture"] = ("http://www.roblox.com/asset/?id="..aid)
			else
				--/ Accessory
				for _, v : Accessory in asset:GetChildren() do
					v.AccessoryType = accessoryType
					v:WaitForChild("Handle").CanQuery = false
					v.Parent = char
				end
			end
			
			return true, string.format("Successfully gave %s accessory %s", player.Name, aid)
		end
		
		for i, aid in aids do
			aid = aid:match("^%s*(.-)%s*$")
			
			if not tonumber(aid) then
				NotificationService:Send(admin, string.format("Could not get product info for %s", aid))
				continue
			else
				local productInfo
				pcall(function()
					productInfo = srv.marketplace:GetProductInfo(aid)
				end)
				
				if not productInfo or productInfo.IsArchived or productInfo.IsLimitedUnique then
					NotificationService:Send(admin, string.format("Item %s is invalid or deleted", aid))
					continue
				end
				
				local result, msg = ApplyItem(aid, productInfo)
				if not result then
					NotificationService:Send(admin, string.format("Could not give %s | %s", aid, msg or "An unknown error has occurred"))
				elseif result and msg then
					NotificationService:Send(player, msg)
				end
			end
		end
		
		return true
	end
}

Any help is much appreciated!

so roblox adds a limit to assets to users who own them or purchased them, you need to add a thing where it detects if the user owns the asset
srv.insert:LoadAsset(aid). also theres a line that loads the asset uses srv.insert:LoadAsset(aid) but this might fail if the roblox service is having an interruption

local function ApplyItem(aid, productInfo)
    local assetType = productInfo.AssetTypeId
    if (assetType >= 3 and assetType <= 5) or assetType == 9 or (assetType >= 19 and assetType <= 40) or assetType >= 48 then
        return false, "Cannot spawn item"
    end
    
    local limit = limits[assetType]
    local accessoryType = limit and limit[1] or Enum.AccessoryType.Unknown
    if limit then
        local total = char:GetAttribute(assetType) or 0
        if total + 1 > limit[2] then
            return false, string.format("Reached item limit %s/%s", total, limit[2])
        end
        char:SetAttribute(assetType, total + 1)
    end

    -- retries the logic for LoadAsset
    local asset
    for attempt = 1, 3 do
        local succ, err = pcall(function()
            asset = srv.insert:LoadAsset(aid)
        end)
        if succ and asset then
            break
        elseif attempt == 3 then
            return false, err or string.format("Failed to load item %s after multiple attempts.", aid)
        else
            wait(0.5) -- Small delay before retry
        end
    end

    -- Check ownership
    if not srv.marketplace:PlayerOwnsAsset(player, aid) then
        return false, "Player does not own this asset"
    end

    if assetType == 11 then
        --/ Shirt
        local shirt = char:FindFirstChildOfClass("Shirt")
        if shirt then
            shirt:Destroy()
        end
        asset.Shirt.Parent = char
    elseif assetType == 12 then
        --/ Pants
        local pants = char:FindFirstChildOfClass("Pants")
        if pants then
            pants:Destroy()
        end
        asset.Pants.Parent = char
    elseif assetType == 18 then
        --/ Face
        local head = char:WaitForChild("Head")
        local faceDecal = head:FindFirstChildOfClass("Decal")
        if not faceDecal then
            return
        end
        faceDecal["Texture"] = ("http://www.roblox.com/asset/?id="..aid)
    else
        --/ Accessory
        for _, v : Accessory in asset:GetChildren() do
            v.AccessoryType = accessoryType
            v:WaitForChild("Handle").CanQuery = false
            v.Parent = char
        end
    end

    return true, string.format("Successfully gave %s accessory %s", player.Name, aid)
end

Other users have had no issues loading in items that they don’t own, so why check? They use this command to spawn in items they don’t have for their avatar, checking if they own it or not makes the command pretty useless