GameAnalytics - Failed to send events

I recently started using GameAnalytics. It works great, except for the fact that events fail to send frequently.

image

This warning pops up frequently. When I shutdown all servers and joined a server, I checked logs and more than half of the session start events failed to send. This means that my analytics aren’t as accurate as they should be.

I think this is linked to why events are failing:

All 10 processed events

Edit: I should’ve been more clear in my post. I’m using the GameAnalytics Roblox SDK. All I did was install it and set it up with all the default values. No custom events, dimensions, etc.

I took a look at the code where the warning was being sent and here is what I found:

if statusCode == http_api.EGAHTTPApiResponse.BadRequest and responseBody then
    logger:w("Event queue: " .. tostring(#queue) .. " events sent. " .. tostring(#responseBody) .. " events failed GA server validation.")
else
    logger:w("Event queue: Failed to send events.")
end
Whole function
local function processEvents()
    local queue = dequeueMaxEvents()

    if #queue == 0 then
        logger:i("Event queue: No events to send")
        return
    end

    -- Log
    logger:i("Event queue: Sending " .. tostring(#queue) .. " events.")

    local eventsResult = http_api:sendEventsInArray(events.GameKey, events.SecretKey, queue)
    local statusCode = eventsResult.statusCode
    local responseBody = eventsResult.body

    if statusCode == http_api.EGAHTTPApiResponse.Ok and responseBody then
        logger:i("Event queue: " .. tostring(#queue) .. " events sent.")
    else
        if statusCode == http_api.EGAHTTPApiResponse.NoResponse then
            logger:w("Event queue: Failed to send events to collector - Retrying next time")
            for _,e in pairs(queue) do
                if #store.EventsQueue < MAX_AGGREGATED_EVENTS then
                    store.EventsQueue[#store.EventsQueue + 1] = e
                else
                    break
                end
            end
        else
            if statusCode == http_api.EGAHTTPApiResponse.BadRequest and responseBody then
                logger:w("Event queue: " .. tostring(#queue) .. " events sent. " .. tostring(#responseBody) .. " events failed GA server validation.")
            else
                logger:w("Event queue: Failed to send events.")
            end
        end
    end
end

Edit 2: I looked into the code and printed statusCode and responseBody when an event fails to send. Here’s what I got:

statusCode 6 means BadRequest. I’m not sure what to do with this information.
unknown%20(2)

I’ve tried searching around but I haven’t seen anyone post anything similar.

Is there anything I can do about this?

Its hard for me to tell you an issue except for what the error tells us:

From the error it tells us that the event did not pass validation and was rejected - that is all we can gain as to insight in why the error occurred. This sadly doesn’t provide much information and I can’t suggest a reason for failure as the possibilities are huge.

I would assume its to do with the event failing to send from Roblox to where you expect it to end up, Roblox could possibly just send an error over and as such it can likely be assumed that this is an issue on your coding side and not something to do with the site itself. Roblox likely sends some poorly made thing and hence that is why your provider on the other end receives an sdk_error as it couldn’t understand the mess.

I honestly wish you luck and I’m not sure how many people will be able to give you a response - I hope you get a response which helps though. I’d provide snippets of your code for others (because its an even bigger shot in the dark as to why your code doesn’t work if we can’t actually see the code / your method).

Good luck :pray:

1 Like

I should’ve been more clear in my post. I’m using the GameAnalytics Roblox SDK. All I did was install it and set it up with all the default scripts and values. No custom events, dimensions, etc.

I took a look at the code where the warning was being sent and here is what I found:

if statusCode == http_api.EGAHTTPApiResponse.BadRequest and responseBody then
    logger:w("Event queue: " .. tostring(#queue) .. " events sent. " .. tostring(#responseBody) .. " events failed GA server validation.")
else
    logger:w("Event queue: Failed to send events.")
end
Whole function
local function processEvents()
    local queue = dequeueMaxEvents()

    if #queue == 0 then
        logger:i("Event queue: No events to send")
        return
    end

    -- Log
    logger:i("Event queue: Sending " .. tostring(#queue) .. " events.")

    local eventsResult = http_api:sendEventsInArray(events.GameKey, events.SecretKey, queue)
    local statusCode = eventsResult.statusCode
    local responseBody = eventsResult.body

    if statusCode == http_api.EGAHTTPApiResponse.Ok and responseBody then
        logger:i("Event queue: " .. tostring(#queue) .. " events sent.")
    else
        if statusCode == http_api.EGAHTTPApiResponse.NoResponse then
            logger:w("Event queue: Failed to send events to collector - Retrying next time")
            for _,e in pairs(queue) do
                if #store.EventsQueue < MAX_AGGREGATED_EVENTS then
                    store.EventsQueue[#store.EventsQueue + 1] = e
                else
                    break
                end
            end
        else
            if statusCode == http_api.EGAHTTPApiResponse.BadRequest and responseBody then
                logger:w("Event queue: " .. tostring(#queue) .. " events sent. " .. tostring(#responseBody) .. " events failed GA server validation.")
            else
                logger:w("Event queue: Failed to send events.")
            end
        end
    end
end

I’d recommend printing statusCode and printing responseBody:
That way we can start narrowing down to our issue - research the status code online first.
If you have no responseBody - issue found. The statusCode however should tell you the issue.

(Pretty sure http_api.EGAHTTPApiResponse.BadRequest is just a number and the fancy length is so its easier for people to see all the errors.) :smile:

There’s no responseBody. What does it mean?

(I havent searched what the statusCode means yet, will do now)

I checked the scripts again and found that statusCode 6 means BadRequest

unknown%20(2)

Simplest way to amend that would be to:

  1. Check the data which has been sent is correct. Compare one that does work to one that doesn’t.
  2. Resend the data? Does it only happen every now and then? You could possibly just need to send it to the server again - not sure.
  3. Look up on the SDK why you might have this issue.

After trying to figure out what’s wrong, I happened to come to the realisation that the event only fails to send if the player is on mobile.

I also found that there is a debug log and I turned it on. Here’s what I got:

Sent succesfully

Failed to send

Here’s the code where it prints Sending 'events' URL: and subsequently body: :

Code
logger:d("Sending 'events' URL: " .. url)

-- make JSON string from data
local payload = HTTP:JSONEncode(eventArray)
local authorization = encode(payload, secretKey)

local res
local success, err = pcall(function()
    res = HTTP:RequestAsync({
        Url = url,
        Method = "POST",
        Headers = {
            ["Authorization"] = authorization
        },
        Body = payload
    })
end)

if not success then
    logger:d("Failed Events Call. error: " .. err)
    return {
        statusCode = http_api.EGAHTTPApiResponse.UnknownResponseCode,
        body = nil
    }
end


logger:d("body: " .. res.Body)
Whole function
function http_api:sendEventsInArray(gameKey, secretKey, eventArray)
    if not eventArray or #eventArray == 0 then
        logger:d("sendEventsInArray called with missing eventArray")
        return
    end

    -- Generate URL
    local url = baseUrl .. "/" .. gameKey .. "/" .. self.eventsUrlPath
    if RunService:IsStudio() then
        url = baseUrl .. "/5c6bcb5402204249437fb5a7a80a4959/" .. self.eventsUrlPath
    end

    logger:d("Sending 'events' URL: " .. url)

    -- make JSON string from data
    local payload = HTTP:JSONEncode(eventArray)
    local authorization = encode(payload, secretKey)

    local res
    local success, err = pcall(function()
        res = HTTP:RequestAsync({
            Url = url,
            Method = "POST",
            Headers = {
                ["Authorization"] = authorization
            },
            Body = payload
        })
    end)

    if not success then
        logger:d("Failed Events Call. error: " .. err)
        return {
            statusCode = http_api.EGAHTTPApiResponse.UnknownResponseCode,
            body = nil
        }
    end


    logger:d("body: " .. res.Body)
    local requestResponseEnum = processRequestResponse(res, "Events")

    -- if not 200 result
    if requestResponseEnum ~= http_api.EGAHTTPApiResponse.Ok and requestResponseEnum ~= http_api.EGAHTTPApiResponse.BadRequest then
        logger:d("Failed Events Call. URL: " .. url .. ", JSONString: " .. payload .. ", Authorization: " .. authorization)
        return {
            statusCode = requestResponseEnum,
            body = nil
        }
    end

    local responseBody
    ypcall(function()
        responseBody = HTTP:JSONDecode(res.Body)
    end)

    if not responseBody then
        logger:d("Failed Events Call. Json decoding failed")
        return {
            statusCode = http_api.EGAHTTPApiResponse.JsonDecodeFailed,
            body = nil
        }
    end

    -- print reason if bad request
    if requestResponseEnum == http_api.EGAHTTPApiResponse.BadRequest then
        logger:d("Failed Events Call. Bad request. Response: " .. res.Body)
        return {
            statusCode = requestResponseEnum,
            body = nil
        }
    end

    -- all ok
    return {
        statusCode = http_api.EGAHTTPApiResponse.Ok,
        body = responseBody
    }
end

The difference I see is that when the event is sent successfully, it prints body: {}, but when it fails, body: is some table that is incomplete.

What’s the issue here?

Noticed something:
image

It is in the failed to send. The argument doesn’t form properly and as such no wonder it flags a whole error as it never actually finishes the JSON.

Look:


For the argument to be completed it would require 1.3.6"} at the end for it to work.

I’d look into that :eyes:

Yes, that’s what I meant by

The difference I see is that when the event is sent successfully, it prints body: {} , but when it fails, body: is some table that is incomplete.

However, I looked into the code and tried for an hour to figure out why, and I only recently realised that the script does not change body:, but the response does from HttpService:RequestAsync. I think this is an issue on GameAnalytic’s end. Not sure how I’d report this to them tho other than filling out a support ticket which I’ve already done.

Aye its likely an issue on there end. Oh well we tried :laughing:

Hopefully they solve it themselves for you.

Hi @Twinbrotato,

Sorry to hear you have troubles with the events. From the screenshot I can’t see the whole contents of the event trying to be sent (the one that starts with “Event added to queue”). The processed error events suggests it is something to do with validation of the events, which is why I would like to see the rest of the event trying to be sent to see what could cause the problem.

Thanks,
Martin
Lead SDK Developer @ GameAnalytics

Hello, I’m glad you found my post!

Sorry about that, here are screenshots that show the whole information:

Failed to send

Sent succesfully

The only difference I see is the device. So what I did was change the code where the player’s device is set so that when the device is unknown, it sets the device to “uwp_desktop”:

PlayerData.Platform = (PlayerPlatform == "Console" and "uwp_console") or (PlayerPlatform == "Mobile" and "uwp_mobile") or (PlayerPlatform == "Desktop" and "uwp_desktop") or ("uwp_desktop")

Previously, it was like this:

PlayerData.Platform = (PlayerPlatform == "Console" and "uwp_console") or (PlayerPlatform == "Mobile" and "uwp_mobile") or (PlayerPlatform == "Desktop" and "uwp_desktop") or ("unknown")

(Location of code is in GameAnalytics module, line 425)

Ever since I made this change, I haven’t seen any events fail to send in either the GameAnalytics Live feed page where it shows the processed events, or the game console.

This probably made my data unreliable for filtering data between different devices, but I’m willing to sacrifice that in return for events being sent successfully which makes the data much more accurate.

Ok thanks for the reply. Have you checked what PlayerPlatform is actually equal to then? If it is a new value I can update the line.

I’m unable to check for sure but I think PlayerPlatform should be nil

Code where PlayerPlatform is defined:

local PlayerPlatform = "unknown"
    local isSuccessful, platform = Postie.InvokeClient("getPlatform", Player, 15)
    if isSuccessful then
        PlayerPlatform = platform
    end

    --Fill Data
    for key, value in pairs(store.BasePlayerData) do
        PlayerData[key] = PlayerData[key] or value
    end

    store.PlayerCache[Player.UserId] = PlayerData

    PlayerData.Platform = (PlayerPlatform == "Console" and "uwp_console") or (PlayerPlatform == "Mobile" and "uwp_mobile") or (PlayerPlatform == "Desktop" and "uwp_desktop") or ("uwp_desktop")

Client code:

--Services
local GS = game:GetService("GuiService")
local UIS = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Postie = require(ReplicatedStorage.Postie)

--Functions
local function getPlatform()

    if (GS:IsTenFootInterface()) then
        return "Console"
    elseif (UIS.TouchEnabled and not UIS.MouseEnabled) then
        return "Mobile"
    else
        return "Desktop"
    end
end

--Filtering
Postie.SetCallback("getPlatform", getPlatform);

There can only be 3 values- “Console”, “Mobile” and “Desktop”. So the only thing PlayerPlatform could be that isn’t any of those 3 is nil

1 Like

Ok thanks. I have updated the SDK to callback to uwp_desktop if it doesn’t find one of the 3 possible values.

1 Like