Publishing & Deployment Issues May 24, 2026

GX.games HTML5 Upload Receipt build_id Disagrees With Steam Depot build_label - How to Fix

Fix GX.games HTML5 upload receipt build_id mismatch with Steam depot build_label. One build_label source of truth, gx_html5_upload_receipt_v1.json, build_label_smoke_receipt, and multi-channel BUILD_RECEIPT gates.

By GamineAI Team

GX.games HTML5 Upload Receipt build_id Disagrees With Steam Depot build_label - How to Fix

Problem: Your GX.games HTML5 upload returns a receipt JSON with build_id": "gx-2026-05-20-a" (or similar), but the Steam fest install title screen shows fest-demo-2026-05-24-rc2. Support tickets reference one string; your BUILD_RECEIPT row references another—and QA cannot tie a GX browser crash to the NW.js Steam build players actually downloaded.

Who is affected now: HTML5-first micro-studios running GX.games + Steam in parallel per the H2 2026 HTML5 second storefront analysis. You fixed itch MIME and Steam depot names, but GX uploader cache and manual version bumps still let channels diverge during fest week. This is cross-channel label drift, not playtest binary on fest depot (same Steam surface, wrong exe).

Fastest safe fix: Pick one build_label string in repo root VERSION (or CI env) → inject into HTML5 export, GX upload metadata, and Steam NW.js / desktop build → upload both channels from the same git SHA → diff gx_html5_upload_receipt_v1.json vs build_label_smoke_receipt_v1.jsonblock fest visibility / GX publish when strings differ → confirm in-game overlay on both clients.

Direct answer

GX.games and Steam are separate CDNs—they do not share a manifest. If you bump Steam’s build_label after promotion but skip GX re-upload (or GX serves a cached HTML5 bundle), receipts and player-visible labels will disagree. Treat build_label as a release artifact property generated once per commit, not per storefront form field.

Why this issue spikes in 2026

  1. Dual-surface HTML5 studios — GX for discovery, Steam for wishlist/fest—two upload rituals, one tired producer.
  2. GX cache behavior — Old index.html / wasm can remain live after you thought you shipped.
  3. Different ID field names — GX API returns build_id; Steam docs say build_label; teams map them mentally and drift.
  4. Separate definesSTEAM_RELEASE vs GX_BUILD macros diverge when only one export preset updates.
  5. Wednesday smokeBUILD_RECEIPT columns now expect per-channel upload proof, not Steam-only.

Symptoms and search phrases

  • GX developer console receipt build_id ≠ Steam title-screen build_label.
  • Player on GX reports bug; your Steam crash log filter finds no matches.
  • BUILD_RECEIPT has Steam upload row only—GX row missing or stale date.
  • Fest week hotfix: Steam promoted; GX still serves last week’s wasm.
  • playtest_scope_map_v1.json lists gx_public row but nobody re-uploaded GX after fest tag.
  • Support spreadsheet has two “version” columns that stopped matching in May.
  • CI green on Steam job; GX upload job skipped or used latest artifact from wrong branch.

Root causes (check in order)

  1. Manual bump on one channel only — Steam rc3, GX still rc2.
  2. GX CDN / project cache — upload succeeded; live game old.
  3. Steam depot promoted later — GX uploaded from earlier commit.
  4. Different scripting defines — HTML5 export preset not reading same VERSION file.
  5. Separate CI workflows — no shared “release tag” input.
  6. Receipt records wrong field — logged GX project id instead of build_id from response body.
  7. No in-game readout on HTML5 — mismatch found via Discord, not smoke.

Beginner path (first 45 minutes)

Prerequisites: GX.games project access, Steam fest build installed (not editor), one VERSION file in repo (create if missing).

  1. Open live GX.games game URL → pause/menu → note on-screen build_label (add if missing—Step 2).
  2. Install Steam fest demo → note title-screen label (photo).
  3. Download last GX upload receipt from CI artifact or release-evidence/gx/.
  4. Compare three strings: GX overlay, Steam overlay, receipt build_id / build_label.
  5. If any differ → pause GX publish and Steam fest visibility until one commit rebuilds both.

Common mistake: Trusting GX dashboard “last updated” timestamp without opening the live URL in a private window.

Fastest safe fix path

Step 1 — Single build_label source of truth

Create repo-root VERSION (plain text, one line):

fest-demo-2026-05-24-rc2

Wire every export to read it:

Stack Injection
Construct 3 Project property + event copies to HUD Text
GameMaker #macro BUILD_LABEL include from generated header
Godot 4.x Export preset env BUILD_LABEL; autoload BuildInfo
Phaser / custom Webpack DefinePlugin or import.meta.env

Rule: CI sets VERSION from git tag fest-demo-2026-05-24-rc2—humans do not edit per storefront.

Step 2 — Capture GX upload receipt correctly

After GX.games uploader / API publish, persist response body (field names vary by integration—normalize in CI):

{
  "schema": "gx_html5_upload_receipt_v1",
  "uploaded_at_utc": "2026-05-24T21:15:00Z",
  "git_sha": "a1b2c3d4",
  "build_id": "fest-demo-2026-05-24-rc2",
  "gx_project_id": "your-project-slug",
  "live_url": "https://gx.games/games/your-game/your-build/",
  "wasm_mime_ok": true,
  "pass": true
}

Store at release-evidence/gx/gx_html5_upload_receipt_v1.json.
Normalize: map GX API build_id → same string as VERSION file—if API returns opaque hash, also log build_label you sent in upload metadata.

Official: GX.games documentation (verify current uploader fields in your integration version).

Step 3 — Steam side build_label_smoke_receipt

Reuse Steam fest depot build_label help receipt—add channel awareness:

{
  "schema": "build_label_smoke_receipt_v1",
  "channels": [
    {
      "channel": "steam_fest",
      "expected_build_label": "fest-demo-2026-05-24-rc2",
      "installed_build_label": "fest-demo-2026-05-24-rc2",
      "pass": true
    },
    {
      "channel": "gx_html5",
      "expected_build_label": "fest-demo-2026-05-24-rc2",
      "installed_build_label": "fest-demo-2026-05-24-rc2",
      "pass": true
    }
  ],
  "cross_channel_label_collision": false,
  "pass": true
}

Step 4 — CI diff gate (fail closed)

$version = Get-Content -Raw VERSION
$gx = Get-Content release-evidence/gx/gx_html5_upload_receipt_v1.json | ConvertFrom-Json
$steam = Get-Content release-evidence/steam/build_label_smoke_receipt_v1.json | ConvertFrom-Json

if ($gx.build_id -ne $version.Trim()) { throw "GX build_id mismatch VERSION" }
$fest = $steam.channels | Where-Object { $_.channel -eq "steam_fest" }
if ($fest.installed_build_label -ne $version.Trim()) { throw "Steam label mismatch VERSION" }

Run after both upload jobs on the same pipeline run (same git_sha).

Step 5 — BUILD_RECEIPT multi-channel row

Extend BUILD_RECEIPT:

Column Example
build_label fest-demo-2026-05-24-rc2
git_sha a1b2c3d4
gx_upload_ok true
steam_depot_upload_ok true
channel_label_match true

Attach both receipt JSON paths in upload_log array.

Step 6 — GX cache bust smoke

After upload:

  1. Open GX live URL in private window (no service worker from dev session).
  2. Hard refresh (Ctrl+F5) or append ?b=fest-demo-2026-05-24-rc2 query if your loader supports cache bust.
  3. Confirm overlay label matches VERSION.
  4. If stale → re-upload; check GX project “replace build” vs new slot; verify wasm path updated.

Pair with itch.io WASM MIME boot hang when browser loads wrong wasm—not label drift but common on same HTML5 artifact.

Working dev path — playtest_scope_map channel rows

Add explicit channel surfaces:

{
  "surfaces": [
    {
      "surface_id": "gx_public",
      "channel": "gx_html5",
      "build_label": "fest-demo-2026-05-24-rc2",
      "demo_scope": "fest_hour_one"
    },
    {
      "surface_id": "fest_public",
      "channel": "steam",
      "build_label": "fest-demo-2026-05-24-rc2",
      "demo_scope": "fest_hour_one"
    }
  ]
}
Check Pass
Same build_label on both rows when scope matches Yes
Different demo_scope → labels may differ intentionally Documented
git_sha in both receipts equal Yes
GX wasm_mime_ok true for Godot/Construct exports

See playtest isolation playbook for surface tagging—GX public is fest_public or dedicated gx_public per your policy, not playtest.

Verification checklist

  • [ ] VERSION file matches GX receipt build_id / build_label
  • [ ] VERSION matches Steam installed overlay
  • [ ] GX live URL overlay matches after private-window load
  • [ ] gx_html5_upload_receipt_v1.json pass: true
  • [ ] build_label_smoke_receipt_v1.json all channels pass: true
  • [ ] BUILD_RECEIPT channel_label_match: true
  • [ ] Both uploads from same git_sha
  • [ ] Wednesday smoke diff includes GX + Steam columns

Prevention

  1. One pipeline, two upload jobs—sequential, same artifact folder.
  2. Never bump Steam only during fest week without GX job.
  3. Photo/screenshot gate: GX overlay + Steam overlay in CI artifacts.
  4. Document GX cache bust step in facilitator README (sibling to playtest VOD README).
  5. GameMaker export sanity + HTML5 analysis as onboarding reading.

Troubleshooting

Symptom Fix
GX receipt OK, live game old Cache—private window + re-upload; verify wasm URL changed
Steam correct, GX wrong Re-run GX job from fest tag commit
Labels match, behavior differs Different defines—grep STEAM / GX macros; not this article’s label-only drift
Opaque GX build_id hash Store your build_label in upload metadata + receipt
Only Steam in BUILD_RECEIPT Add GX row; block promotion without it
Playtest label on GX Wrong export preset—see Steam playtest on fest depot

FAQ

Is GX build_id the same as Steam BuildID?
No. Steam BuildID is SteamPipe internal. Your team-owned string is build_label (human-readable). Map GX API fields into that string for support triage.

Can we use different labels if demos differ?
Yes—if demo_scope differs, labels should differ and playtest_scope_map must document it. Do not silently diverge when scope is meant to match.

Do we need GX if we only ship Steam?
No—skip GX receipt columns. This help applies when both channels are live.

Construct-only on GX, GameMaker on Steam?
Still use one build_label per release intent if QA correlates bugs across channels; note engine in receipt notes field.

Related links

One build_label per release commit—GX receipts and Steam depots are two upload buttons, not two version truths.