Skip to content

sanity deploy: persistent HTTP 500 on bundle upload step for project ya36kz5r — 7 traceIds, client-side ruled out #1133

Open

Description

@charliepickard

Describe the bug

Running sanity deploy consistently fails with HTTP 500 on the multipart bundle upload step (POST /v2024-08-01/projects/ya36kz5r/user-applications/{id}/deployments) for project ya36kz5r. The schema lexicon and manifest upload steps that come before it succeed cleanly every time. Failure is 100% reproducible — 7 attempts produced 7 distinct traceIds with identical failure points. Server response is always:

{
  "statusCode": 500,
  "error": "Internal Server Error",
  "message": "An internal server error occurred"
}

Response headers of note: x-served-by: Brett, sanity-gateway: k8s-gcp-eu-w1-prod-ing-01.

To Reproduce

  1. Open Terminal and cd into the Studio project directory
  2. Run npx sanity deploy
  3. CLI completes schema lexicon and descriptor upload steps successfully
  4. CLI starts uploading the static bundle (~7.2 MB) to /v2024-08-01/projects/ya36kz5r/user-applications/{id}/deployments
  5. Bundle upload returns HTTP 500 — deploy aborts

Expected behavior

Bundle upload completes, hosted Studio deploys to https://centraspot.sanity.studio.

Screenshots

Not applicable — CLI failure, not a UI bug. Response body and headers are quoted above.

Which versions of Sanity are you using?

@sanity/cli (global)   6.6.0 (up to date)
@sanity/cli            6.6.0 (up to date)
@sanity/vision         5.26.0 (up to date)
sanity                 5.26.0 (up to date)

What operating system are you using?

macOS (MacBook Air)

Which versions of Node.js / npm are you running?

node: v24.13.1
npm:  11.8.0

Additional context

Project / plan:

  • Project ID: ya36kz5r
  • Dataset: production
  • Plan: Growth Trial (28 days remaining as of 2026-05-27)
  • Studio hostname slot: centraspot (also tested centraspot-studio)

TraceIds collected (chronological):

  1. bbcb7e07e3076eef60ca5fef9db3b6eb
  2. 9635605001e8f4830f351e7990156725
  3. 37f48c0d4b7bb41a6c1a616f3c2c8e97
  4. ff7362682c12db8d0bf75bb8c03150f9
  5. 7b32f4c70fe60abb34d0a66923e6883b
  6. 6346a459c1c800b6fa65ca93d261ba88
  7. 327a29cd932704ef5a239c7140dfee7b

Client-side variables ruled out:

Variable Values tested Result
@sanity/cli v3.99, v6.6.0 latest Both fail
sanity runtime v3.99, v5.26 latest Both fail
React 18.3, 19.2 latest Both fail
Config syntax legacy autoUpdates: false, new deployment: { autoUpdates: false } Both fail
Hostname slot original centraspot, secondary centraspot-studio, recreated centraspot after deleting both originals from the manage dashboard All three fail identically

The delete-and-recreate test (traceId sanity-io/sanity#7) is the strongest signal: a brand-new user-application record on v6.6 / v5.26 / React 19 from a clean slate still fails at the same point, eliminating stale slot state.

Hypotheses I cannot test from outside:

  • Growth Trial plan tier restriction on hosted Studio deploys for new projects
  • Project-level account flag on ya36kz5r
  • Backend bug affecting this project's user-application records

Impact / workaround in place:

Schema manifest path works fine — platform app reads (GROQ) and writes (HTTP mutate) unaffected. Local npx sanity dev workaround functional. Only the hosted browser editor at centraspot.sanity.studio is blocked.

Also posted in Discord #help (https://www.sanity.io/discord) — opening here for a public, indexed bug record. Happy to provide bundle hash, full verbose CLI output, package.json, sanity.config.ts, or sanity.cli.ts on request.

Security issue?

No — this is an infrastructure availability issue, not a security one.

Activity

  1. transferred this issue fromsanity-io/sanityon May 26, 2026
  2. ChrisNolan commented on May 26, 2026

    @ChrisNolan

    With your deployment key in the config, try adding in the appId (and maybe other fields) and see if that helps.

    Reference: discord post

  3. charliepickard commented on May 26, 2026

    @charliepickard
    Author

    Thanks for the suggestion. Found the user-application ID in sanity.io/manage → Studios (the centraspot.sanity.studio slot, Version N/A confirming it was created during a prior failed deploy but never received a bundle). Pinned it as deployment.appId in sanity.cli.ts:
    tsdeployment: { appId: "jyqh9ima6hqs38lef6k0w5l1", autoUpdates: false },
    Re-ran npx sanity deploy — same 500 at the same step, new traceId: 0872df6335a6135648435aaa16a9c01e (8th distinct ID now).
    So pinning the appId vs. letting the CLI auto-resolve it from studioHost makes no difference to the failure mode. Failure is at the multipart bundle upload to POST /v2024-08-01/projects/ya36kz5r/user-applications/jyqh9ima6hqs38lef6k0w5l1/deployments, regardless of whether the deployment endpoint is hitting a new or existing app record.

  4. charliepickard commented on May 26, 2026

    @charliepickard
    Author

    Quick update — pinning deployment.appId (thanks for the suggestion) made no difference, but a DEBUG=* re-run gave us a useful new signal.
    9th traceId: b5d77da32a8d6aaa452e5db773935e4a
    Failure shape identical to the previous 8:

    PUT /v2025-03-01/projects/ya36kz5r/datasets/production/schemas → 201 ✅
    POST /v2025-03-01/descriptors/claim → 200 ✅
    POST /v2024-08-01/projects/ya36kz5r/user-applications/jyqh9ima6hqs38lef6k0w5l1/deployments → 500 in 495ms

    The new observation is that response time. 495ms is far too fast for a multipart bundle upload to have actually been received and processed — it strongly suggests the failure is during the lookup/validation of the user-applications/{appId} record itself, before the backend ever reads the bundle bytes. Same x-served-by: Brett, same sanity-gateway: k8s-gcp-eu-w1-prod-ing-01 as the previous 8 attempts.
    Now spanning: CLI v3.99 → v6.6, sanity v3.99 → v5.26, React 18 → 19.2, 3 distinct hostname slots, 2 user-application records (auto-resolved + pinned). All fail at the same endpoint with the same shape. Schemas keep deploying fine to the API every time.
    Specific ask: could someone on Sanity's side check whether the user-application record jyqh9ima6hqs38lef6k0w5l1 (under project ya36kz5r) is in a corrupted/half-created state, and if so delete it server-side so the CLI can create a fresh one on the next deploy attempt? After 9 identical failures spanning every client-side variable we can change, that feels like the remaining unexplored variable.
    Happy to share the full DEBUG=* log (16,910 lines, ~2MB) privately if helpful.

  5. charliepickard commented on May 26, 2026

    @charliepickard
    Author

    One more data point.
    Ran the deploy with deployment.appId omitted from sanity.cli.ts to try to force a brand-new user-application record. CLI v6.6 resolved the appId from studioHost: 'centraspot' and hit the exact same jyqh9ima6hqs38lef6k0w5l1 record anyway — the POST URL was identical to all prior attempts. So the appId pin we added per the earlier suggestion has been functionally a no-op against this failure mode (the CLI was going to use that record regardless via hostname lookup).
    10th traceId: 1dfdd38ac7a416d04592afa6aff7f98f. Same 500, same ~480ms response, same headers.
    Tally of what we've now ruled out across the 10 attempts:

    CLI version (v3.99 and v6.6 both fail)
    sanity runtime version (v3.99 and v5.26 both fail)
    React major (18 and 19.2 both fail)
    studioHost slot (3 distinct hostnames — centraspot, centraspot-studio, and recreated centraspot after dashboard delete — all fail)
    user-application record (3 distinct records all fail)
    appId pinned vs auto-resolved (no difference; CLI resolves from studioHost either way)

    All 10 attempts fail at POST /v2024-08-01/projects/ya36kz5r/user-applications/{appId}/deployments with the same 500 / ~480ms / x-served-by: Brett / sanity-gateway: k8s-gcp-eu-w1-prod-ing-01 signature. Schemas + descriptors continue to deploy fine to the API every time.
    At this point the only remaining variable is server-side state on project ya36kz5r. Could someone on Sanity's side take a look at whatever the user-applications service is doing when it receives a POST for any record under this project? Happy to share full DEBUG=* logs privately.

  6. ChrisNolan commented on May 26, 2026

    @ChrisNolan

    I believe the issue is the combination of 'studioHost' and 'appId'. I recall that they were deprecating studioHost, or moving it to a different part of the config or something? Hopefully someone on the team can verify (or you can go digging in the source code as you seem to know what you're doing). Specially focus on the the changelog back around the v5.15 daays... wait

    Image

    Found that reference. So yeah... try using the appId and no studioHost and see if that gets raound the error. There is probably some entry somewhere for the studioHost which is 'corrupted' and it keeps pulling it out? A fresh appId might be what you need? Not sure.

    Wouldn't it be nice to just because to tail the logs on the other side to see why the stack of the error 500 😉

  7. charliepickard commented on May 26, 2026

    @charliepickard
    Author

    Huge thanks to @ChrisNolan — your studioHost-deprecation hint cracked this open.
    The hint sent me into the CLI source. The deprecation comment is right there in findUserApplicationForStudio.js ("As a fallback, if studioHost (deprecated) is configured..."). What it pointed me at was the deeper version of what you proposed: not just "drop studioHost from config" — which turns out to be byte-equivalent to keeping it once appId is set, because the appId branch is checked first and the appHost branch never runs — but test a code path that doesn't bind a studioHost at all server-side. That's --external mode.
    Tried npx sanity deploy --external --url https://centraspot-external-test.example.com (appId omitted from sanity.cli.ts so the CLI would create a fresh record).
    POST /v2024-08-01/projects/ya36kz5r/user-applications/z32hh3l0121hpfaoh4v4jcd2/deployments → 201 Created in ~950ms. Deployment ID t4rsbxljiyi8gdw2m1irg554. "Studio registered" success.
    Same project, same auth, same CLI v6.6, same descriptors/claim flow (200) before it, same /user-applications/{id}/deployments URL pattern. Only differences vs. the failing internal deploys:

    urlType: 'external' instead of 'internal'
    No tarball in the multipart body (verified at services/userApplications.js:151 — if (tarball) formData.append(...))
    No studioHost binding on the record

    The user-applications service for ya36kz5r is not broken; only the internal-deploy path is. The 500s we've collected 10 traceIds for happen in something internal deploys do and external deploys skip — likely either tarball storage, or the studioHost / DNS / CDN provisioning that attaches a *.sanity.studio hostname to internal records. Chris's "probably some entry somewhere for the studioHost which is corrupted" intuition was exactly the right shape; the bisection just lived one level above what a config tweak could reach.
    Response timing reinforces it: external took ~950ms (real work end-to-end), internal 500s all came back in ~480ms (failing fast, before any bundle processing).
    Two records on Sanity's side worth comparing:

    Failing internal: jyqh9ima6hqs38lef6k0w5l1 (urlType: internal, studioHost: centraspot)
    Working external: z32hh3l0121hpfaoh4v4jcd2 (urlType: external, no studioHost)

    Both under project ya36kz5r. If someone on the team can pull the internal record's processing path server-side and look at what happens between the POST hitting the controller and the 500 coming back, that should pinpoint the broken step. Happy to keep the external test record in place as a control until the internal path is fixed.
    And to Chris's parting wish — "wouldn't it be nice to just tail the logs on the other side" — couldn't agree more 😄. Thanks again for the lead.

  8. ChrisNolan commented on May 26, 2026

    @ChrisNolan

    :person_bowing::skin-tone-4: Glad you got to the bottom of it as it were and your excelling debugging should give the CLI team enough to get the backend team to not error in these scenarios anymore. Glad my prompts where enough to lead you to the workaround.

    And awesome you kept both the discord and the github updated for those who discover this issue via different routes. In an ideal world the discord bot would link automatically 🤷 imo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions