ServerOps.ggbeta
Developers

Error handling

The ServerOps error envelope format and all error codes.

Error handling

All errors from the ServerOps API use a consistent JSON envelope. This makes it straightforward to write a single error handler that covers all endpoints.

Error envelope

{
  "error": {
    "code": "not_found",
    "message": "file not found"
  }
}
  • code: a stable machine-readable identifier. Use this in your code for branching logic.
  • message: a human-readable description. Do not rely on the exact wording - it may change. Use code for logic.

HTTP status codes

StatusMeaning
200 OKRequest succeeded
201 CreatedResource created (uploads, log ingestion)
400 Bad RequestRequest body or parameters are invalid
401 UnauthorizedToken missing or invalid
403 ForbiddenToken does not have the required scope
404 Not FoundResource does not exist
409 ConflictDuplicate request or state conflict
413 Content Too LargeFile exceeds the size limit for your plan
415 Unsupported Media TypeFile type is not allowed
429 Too Many RequestsRate limit or quota exceeded
500 Internal Server ErrorUnexpected server error

Error codes

CodeStatusDescription
unauthorized401Token missing or revoked
forbidden403Token lacks required scope
not_found404Resource does not exist
invalid_input400Request body failed validation
quota_exceeded429Plan quota exhausted
rate_limited429Too many requests in the time window
file_too_large413File exceeds plan limit
unsupported_type415File MIME type not allowed
internal_error500Unexpected server error

Quota exceeded response

When a quota is exceeded the error body includes a snapshot of all your current metrics so you know exactly what was hit:

{
  "error": {
    "code": "quota_exceeded",
    "message": "storage quota exceeded",
    "snapshot": {
      "storage_bytes": { "used": 10737418240, "limit": 10737418240 },
      "file_count": { "used": 4821, "limit": 10000 },
      "bandwidth_bytes": { "used": 53687091200, "limit": 107374182400 }
    }
  }
}

Handling errors in code

FiveM Lua

PerformHttpRequest(url, function(statusCode, responseBody)
    if statusCode == 200 or statusCode == 201 then
        local response = json.decode(responseBody)
        -- success
    elseif statusCode == 429 then
        -- rate limited or quota exceeded
        local err = json.decode(responseBody)
        if err and err.error and err.error.code == "quota_exceeded" then
            print("Quota exceeded. Upgrade your plan at serverops.gg/dashboard/billing")
        else
            print("Rate limited. Retrying in 10 seconds...")
        end
    elseif statusCode == 401 then
        print("Invalid token. Check your server.cfg")
    else
        local err = json.decode(responseBody)
        print("ServerOps error: " .. (err and err.error and err.error.code or "unknown"))
    end
end, "POST", body, headers)

Roblox Luau

local ok, result = pcall(function()
    return HttpService:RequestAsync(requestOptions)
end)

if ok and result.Success then
    local data = HttpService:JSONDecode(result.Body)
    -- success
elseif ok then
    local err = pcall(function() return HttpService:JSONDecode(result.Body) end)
    warn("[ServerOps] Error " .. result.StatusCode .. ":", result.Body)
else
    warn("[ServerOps] HTTP request failed:", result)
end

Retrying on 429

For rate limit errors (rate_limited), implement exponential backoff:

  1. On the first 429, wait 1 second and retry.
  2. On the second 429, wait 2 seconds.
  3. On the third 429, wait 4 seconds.
  4. Stop retrying after 3 attempts and log the failure.

For quota errors (quota_exceeded), do not retry - the request will keep failing until the quota resets or you upgrade your plan. Log the error and alert your team.

On this page