{"record":{"id":"1c7778b417fb5ad9","repo":"anomalyco/sst","slug":"failed-to-complete-asset-upload-no-completion-jw","errorCode":null,"errorMessage":"failed to complete asset upload - no completion JWT received","messagePattern":"failed to complete asset upload - no completion JWT received","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/server/resource/cloudflare-worker-assets.go","lineNumber":163,"sourceCode":"\twg.Wait()\n\tclose(errChan)\n\tclose(jwtChan)\n\n\t// Check for any errors\n\tfor err := range errChan {\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t}\n\n\t// Get completion JWT (from the last bucket response)\n\tvar completionJwt string\n\tfor jwt := range jwtChan {\n\t\tcompletionJwt = jwt\n\t}\n\n\tif completionJwt == \"\" {\n\t\treturn \"\", fmt.Errorf(\"failed to complete asset upload - no completion JWT received\")\n\t}\n\n\treturn completionJwt, nil\n}\n\nfunc (r *WorkerAssets) uploadAssetManifest(accountId, scriptName, apiToken string, manifest AssetManifest) (*InitializeAssetsResponse, error) {\n\turl := fmt.Sprintf(\"https://api.cloudflare.com/client/v4/accounts/%s/workers/scripts/%s/assets-upload-session\", accountId, scriptName)\n\n\tjsonBody, err := json.Marshal(map[string]interface{}{\n\t\t\"manifest\": manifest,\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treq, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonBody))\n\tif err != nil {\n\t\treturn nil, err","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/server/resource/cloudflare-worker-assets.go#L145-L181","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-run the deploy; transient Cloudflare asset-upload API issues often resolve on retry.","Log the raw HTTP status/body from each bucket upload in uploadAssets to see why no completion JWT was returned.","Verify the script name and account ID are correct so the upload session targets an existing Worker.","Check that initResponse.Buckets was non-empty and each bucket upload actually hit the /workers/assets/upload endpoint with the session JWT.","Upgrade the platform build / sst CLI in case this known race or empty-response handling has been fixed upstream."],"exampleFix":"// before (uploadAssets returns result.Result.Jwt which may be empty)\nreturn result.Result.Jwt, nil\n// after\nif result.Result.Jwt == \"\" {\n\treturn \"\", fmt.Errorf(\"asset bucket upload returned no completion JWT (HTTP %d)\", resp.StatusCode)\n}\nreturn result.Result.Jwt, nil","handlingStrategy":"retry","validationCode":"// pre-flight: verify script exists and token works before deploy\ncurl -sf -H \"Authorization: Bearer $CF_API_TOKEN\" \\\n  \"https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/workers/scripts/$SCRIPT_NAME\" \\\n  || echo \"script or token invalid - asset upload session will fail\"","typeGuard":null,"tryCatchPattern":"err := deployAssets(ctx)\nif err != nil && strings.Contains(err.Error(), \"no completion JWT received\") {\n    // transient/empty response: retry deploy once or twice with backoff\n    time.Sleep(5 * time.Second)\n    err = deployAssets(ctx)\n}\nif err != nil { return fmt.Errorf(\"asset deploy failed: %w\", err) }","preventionTips":["Don't mutate the asset directory during a deploy","Retry asset deployments once on JWT-related failures","Pin and monitor the Cloudflare API version used by the platform","Log bucket upload responses so empty-JWT cases are diagnosable"],"tags":["cloudflare","workers-assets","jwt","upload"],"backgroundTag":"jwt-token-missing-from-response","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}