question

alexm-1 avatar image
alexm-1 asked

Uploading custom server fails with "Invalid build package"

When uploading a build via the GameManager, everything works fine. However, we're attempting to upload via web APIs, the build ultimately always fails with the game manager reporting the status as "Invalid build package". I'm looking for help in determining why this is. All the API requests are successful, including the file upload, and the game manager offers no diagnostic information other than those three words of status. What am I doing wrong or omitting? How can I get better information about what's going wrong and why the package is invalid so that I can attempt to fix the problem?

Details

We are attempting to automate the build process, which includes uploading a Unreal Engine 4 dedicated server package as a custom PlayFab server, via python. When reviewing output from the upload scripts, there are no obvious problems: all HTTP requests are successful, and even the initial status returned from the AddServerBuild call shows no errors:

Uploading C:\knl_v\VStagedBuilds\StagedPackages\Test004.zip: 379107325 bytes...
POST 'https://54A34.playfabapi.com/Admin/GetServerBuildUploadUrl'...
PUT 'https://gamebuild-playfab-live.s3-accelerate.amazonaws.com/54a34/Test004.zip?X-Amz-Expires=3600&x-amz-security-token=IQoJb3JpZ2luX2VjEFMaCXVzLXdlc3QtMiJGMEQCICQoGAD5xf6rXSiEIbNuU2K4GrBA2cBopPW1MpyvrJreAiBmDphWLq22rDO%2Bwxo7XI67w2xukzsvAcSv2pvkxz8ceirbAgis%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDM4ODEyODAzOTYzMyIMBgYTSupPKp6W97TkKq8CBXTMH%2BZf7sKjramTZCDdvOPJ4MSFSnLElLFgmAKKS71CgQyPEPm1P9zxGwfeD0hghajhLYSrE4bheyUTNMMCZKp6lABrolp4h0wPPhkWAnDMPfOr2QgV6TftDukMSbNR70g7Rf3JCKRu%2FfJNPPHeKyd46iQZhpza1C1FashSDbg8wXUEWxXv51WXm5zvNHNflFrCbVPJ1%2FsPXlHCJ2KgVTtkM7tUW9LPSRg2GxZryXkiEuFuyzMDGBzhz%2FZe8oaMzDaiqLl620Ujy%2FsCb99XjlweCNqnzfvcHlHNedEq2CjBQ1mgtXtrAoHDRsUoQqf7oPAOaoVWDqxw1NEFsLI6aC%2FI9q62rn87aPI2L3kY9Hhwc93WxqT3h4UDyYomZjrI%2B5pfdzTMHSYAkoZB5ZFkMLP26e8FOs4C4lc7lec6Gd8IwfaL9kIdeZD3IChhik4txlQoPQC2tCm9MElaDWj6ecv9jRPzkdEdNBXv4QdHRSgMdlkO6OJbNdyDPPtA83VoM21deT18D8%2BnUoHwXJ32v5SXd22SvZQUltE07Mt61nnMyB08rUcFYOA7ExatGyOgKjF%2BxQbmTNKzzPWegklLxB1Vzlvs19J%2B64iig7sxZjCvb2f3%2BvCTbamNRNz9A3tjrRGWwDuv9hN02zGoQ4Qr1xJ2V7vdc%2FeITGQGePBc6gTS16r3v7CmIY3K9DLUbEbootG7CuzHW7UHkZclp4V9hhBIn8QnP5OCZERfhSKpLyfgCpqmyrzMHSRKpoTW7eUr5%2FhYOfCkWdAL%2FaQktPUUalIVyXCrWwSo9XHD4Z0Omjphew%2BYf2yoCp96dUM0c43qQQASCKSP9g7ALPueGTnrLKK2lbIPlg%3D%3D&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ASIAVUXR34LIRXIZN6VR/20191218/us-west-2/s3/aws4_request&X-Amz-Date=20191218T201048Z&X-Amz-SignedHeaders=content-type;host;x-amz-security-token&X-Amz-Signature=4379147c2b52cd06d5d94de3b7dd9ef33bc1c5e2577045a901a677771c2884a7'...
HTTP Status: OK (200)
POST 'https://54A34.playfabapi.com/Admin/AddServerBuild'...
HTTP Status: OK (200)
{   'code': 200,
    'data': {   'ActiveRegions': ['USCentral'],
                'BuildId': 'Test004',
                'MaxGamesPerHost': 10,
                'MinFreeGameSlots': 1,
                'Status': 'Validating',
                'Timestamp': '2019-12-18T20:10:49.1Z',
                'TitleId': '54A34'},
    'status': 'OK'}
Uploaded Build: 2019-12-18T20:10:49.1Z Test004 54A34: Validating

However, when subsequently checking the status of the build in the build manager, it says "Invalid build package". The package itself is just a zip file, and I've double checked that it's in the appropriate location and is otherwise a well-formed, boring archive. If I upload the same archive via the game manager, the process works fine and the build status becomes 'Available' after validation, so I don't think it's any problem with the package file itself.

For the upload, I'm simply PUT'ing the file to the pre-authorized URL; this works in the sense that, as seen above, the HTTP request is successful. I'm using the python requests library for the upload, specifically:

response = requests.put(upload_url,
    headers={'Content-Type' : 'application/x-zip-compressed'},
    files={f'{build.build_id}.zip': zip_stream},
)

Where upload_url has the values as seen in the previous log (ie. the AWS URL returned from

GetServerBuildUploadUrl), and zip_stream is a file stream opened for byte reading using the python open(...) method. As seen in the logs, the above call returns status 200.

TL;DR

There's no obvious client-side issue, and the same package archive is valid when I upload via the game manager. Please, any help determining why when using the web API the package status becomes "Invalid build package" would be appreciated, as this is currently a blocker for our build automation.

3 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Seth Du avatar image Seth Du ♦ commented ·

It seems the server build is uploaded successfully. I am wondering how do you craft AddServerBuild request because there was a similar case, which is caused by the ExecutablePath not set correctly. Is it in the root directory?

0 Likes 0 ·
alexm-1 avatar image alexm-1 Seth Du ♦ commented ·

I'm constructing the call as follows, with it's corresponding response also shown (command-line template elided, as it then exceeds the 1200 character limit on responses in this forum):

POST 'https://54A34.playfabapi.com/Admin/AddServerBuild'...
{   'ActiveRegions': ['USCentral'],
    'BuildId': 'Test007',
    'CommandLineTemplate': ...
    'ExecutablePath': 'BBR/Binaries/Win64/BBRServer.exe',
    'MaxGamesPerHost': 10,
    'MinFreeGameSlots': 1}
HTTP Status: OK (200)
{   'code': 200,
    'data': {   'ActiveRegions': ['USCentral'],
                'BuildId': 'Test007',
                'MaxGamesPerHost': 10,
                'MinFreeGameSlots': 1,
                'Status': 'Validating',
                'Timestamp': '2019-12-19T19:21:15.896Z',
                'TitleId': '54A34'},
    'status': 'OK'}

The path used for the ExecutablePath value is identical to that successfully used when uploading the same archive manually. I've also tried using the same path with backslashes as well, but this has the same result. Headers used are:

{'Content-Type' : 'application/json', 'X-SecretKey' : secret_key}

Where secret_key is taken from the game manager for title 54A34.

0 Likes 0 ·
alexm-1 avatar image alexm-1 Seth Du ♦ commented ·

I've also tried the upload without specifying any but the documented required parameters to AddServerBuild (ie. only BuildId, MaxGamesPerHost, and MinFreeGameSlots). This still results in the "Invalid build package" message. I've also tried uploading the file using a slightly modified method:

with open(package_zip_file, 'rb') as zip_stream:
    headers = {
        'Content-Type' : 'application/x-zip-compressed',
    }
    files = {
        'file' : (f'{build_id}.zip', zip_stream, 'application/x-zip-compressed')
    }
    response = requests.put(upload_url,
        headers=headers,
        files=files
    )

This also results in the invalid build package result.

What is the expected way to upload the file? The documentation only states:

the complete Zip file can then be uploaded ... to the URL you get back from a call to GetServerBuildUploadUrl... the Content-Type of the upload should be application/x-zip-compressed.

Please be as specific as possible.

0 Likes 0 ·
Seth Du avatar image
Seth Du answered

I have tested uploading the server build and there is no error reported. The whole process is divided into 3 parts:

  1. Call GetServerBuildUploadUrl API to get an upload URL, where Build ID is defined
  2. I manually edit the zip file name as {build ID}.zip before upload, and add Content-Type as application/x-zip-compressed in the request header, then upload server build. There is some information in response header but the body part is empty.
  3. Then call AddServerBuild to deploy the server build, I use slash to locate the server build executable. Here is the sample request:
{
  "BuildId": "5.0.2",
  "CommandLineTemplate": ...,
  "ExecutablePath": "anothertest/PlayFabGameServerClientExample.exe",
  "ActiveRegions": [
    "USEast"
  ],
  "Comment": "Testing new IAP methods",
  "MaxGamesPerHost": 5,
  "MinFreeGameSlots": 1
}

backslash will report error because the format is not valid. Can I see the absolute direcotry for executable file ?

4 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

alexm-1 avatar image alexm-1 commented ·

1. "Can I see the absolute direcotry for executable file"?

I've already shown this in the previous post: BBR/Binaries/Win64/BBRServer.exe

2. "I manually edit the zip file name as {build ID}.zip before upload, and add Content-Type as application/x-zip-compressed in the request header, then upload server build. There is some information in response header but the body part is empty."

When I asked if you could be as specific as possible previously, I was talking about this step. I'm already aware of the broad outlines of how to upload as outlined in the online documentation, and am following the same steps as you are. How exactly are you uploading the archive after obtaining the URL from GetServerBuildUploadURL? How can I test if the archive I'm using is "valid" for purposes of upload? Can you upload a copy of the scripts you're using, or would it help to see the full code of scripts I'm using? What other errors might explain the "invalid build package" error besides the ExecutablePath format? As I said yesterday, the executable path appears to be a red herring: even if I omit this parameter from the call to AddServerBuild, I get the same error. How then can it be part of the issue?

0 Likes 0 ·
alexm-1 avatar image alexm-1 commented ·

Also, can you show the header response information from successful archive upload (specifically, just the upload of the file after GetServerBuildUploadURL and before AddServerBuild) so that I can compare to what I'm seeing on my side?

0 Likes 0 ·
alexm-1 avatar image alexm-1 commented ·

In general, is there any way other than to go through the entire upload process (ie. GetServerBuildURL, upload archive, AddServerBuild) to validate the method I'm using to upload the archive (ie. just to validate step 2)?

0 Likes 0 ·
Seth Du avatar image Seth Du ♦ alexm-1 commented ·

I am using Postman to upload the build, the response return from the URL is:

Can you try to reproduce the steps on Postman so that we may narrow down this issue.

0 Likes 0 ·
brandon@uprootstudios.com avatar image
brandon@uprootstudios.com answered

@alexm-1 While I can't offer a valuable solution to this issue specifically, I can recommend that you use my PlayFab Admin tool to upload your build and create a server build (we use the PF web API to do the build creation but the actual uploading is done via the Azure Storage API).

https://github.com/bphillips09/PFAdmin/

1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Seth Du avatar image Seth Du ♦ commented ·

I assume @alexm-1 is using the Legacy Multiplayer Server feature. The URL returned from API is form Amazon AWS.

0 Likes 0 ·
alexm-1 avatar image
alexm-1 answered

Ultimately found the issue here was in how I was attempting to perform the upload -- specifically, it is required to PUT to the URL returned from the GetServerBuildUploadURL call, and the body of this request must contain the zipped byte data; no other method of attaching the payload (ie. as form or multipart data) works.

It would be nice if the documentation were a little more clear on this point, rather than just repeating generically to "upload", as there are many ways to upload a file, while only this method is valid (at least, in my experience dealing with this issue) with respect to uploading the build. In hindsight, that the content-type was specified as x-zip-compressed should have tipped me off to this, but some explicit notes in the documentation would avoid any potential ambiguity.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.