anomalyco/sst · error

failed to complete asset upload - no completion JWT received

Error message

failed to complete asset upload - no completion JWT received

What it means

This error is thrown by handleUpload after all asset-upload buckets finish and the collected completion JWTs are drained from jwtChan. It means the worker pool finished without any worker returning a final completion JWT from Cloudflare's asset upload endpoint, even though buckets were processed and no explicit error surfaced. The completion JWT is required to activate the uploaded assets, so without it the deployment cannot be finalized.

Source

Thrown at pkg/server/resource/cloudflare-worker-assets.go:163

	wg.Wait()
	close(errChan)
	close(jwtChan)

	// Check for any errors
	for err := range errChan {
		if err != nil {
			return "", err
		}
	}

	// Get completion JWT (from the last bucket response)
	var completionJwt string
	for jwt := range jwtChan {
		completionJwt = jwt
	}

	if completionJwt == "" {
		return "", fmt.Errorf("failed to complete asset upload - no completion JWT received")
	}

	return completionJwt, nil
}

func (r *WorkerAssets) uploadAssetManifest(accountId, scriptName, apiToken string, manifest AssetManifest) (*InitializeAssetsResponse, error) {
	url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%s/workers/scripts/%s/assets-upload-session", accountId, scriptName)

	jsonBody, err := json.Marshal(map[string]interface{}{
		"manifest": manifest,
	})
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		return nil, err

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Re-run the deploy; transient Cloudflare asset-upload API issues often resolve on retry.
  2. Log the raw HTTP status/body from each bucket upload in uploadAssets to see why no completion JWT was returned.
  3. Verify the script name and account ID are correct so the upload session targets an existing Worker.
  4. Check that initResponse.Buckets was non-empty and each bucket upload actually hit the /workers/assets/upload endpoint with the session JWT.
  5. Upgrade the platform build / sst CLI in case this known race or empty-response handling has been fixed upstream.

Example fix

// before (uploadAssets returns result.Result.Jwt which may be empty)
return result.Result.Jwt, nil
// after
if result.Result.Jwt == "" {
	return "", fmt.Errorf("asset bucket upload returned no completion JWT (HTTP %d)", resp.StatusCode)
}
return result.Result.Jwt, nil
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: verify script exists and token works before deploy
curl -sf -H "Authorization: Bearer $CF_API_TOKEN" \
  "https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/workers/scripts/$SCRIPT_NAME" \
  || echo "script or token invalid - asset upload session will fail"

Try / catch

err := deployAssets(ctx)
if err != nil && strings.Contains(err.Error(), "no completion JWT received") {
    // transient/empty response: retry deploy once or twice with backoff
    time.Sleep(5 * time.Second)
    err = deployAssets(ctx)
}
if err != nil { return fmt.Errorf("asset deploy failed: %w", err) }

Prevention

When it happens

Trigger: Every bucket upload returned an empty JWT (e.g. Cloudflare responded 202 with an empty result.jwt, or the last upload responses contained no JWT), or all buckets were skipped/failed silently in a way that left jwtChan empty while errChan stayed empty.

Common situations: Cloudflare API behavior changes or partial responses where the final bucket returns an empty completion JWT; flaky uploads where a worker returns early after an error was sent to errChan but the error loop ordering lets the empty-JWT path run; an empty or degenerate bucket set so no upload ever produces a JWT.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/1c7778b417fb5ad9. Report an issue: GitHub.