{"record":{"id":"5aab6edc1012452b","repo":"anomalyco/sst","slug":"failed-to-initialize-assets-upload-http-d-s","errorCode":null,"errorMessage":"failed to initialize assets upload: HTTP %d %s","messagePattern":"failed to initialize assets upload: HTTP (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/server/resource/cloudflare-worker-assets.go","lineNumber":196,"sourceCode":"\n\treq, err := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonBody))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\treq.Header.Set(\"Authorization\", \"Bearer \"+apiToken)\n\n\tclient := &http.Client{Timeout: 30 * time.Second}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\t// print out response body as a string\n\tif resp.StatusCode != http.StatusOK {\n\t\tresponseBody, _ := io.ReadAll(resp.Body)\n\t\treturn nil, fmt.Errorf(\"failed to initialize assets upload: HTTP %d %s\", resp.StatusCode, string(responseBody))\n\t}\n\n\tvar result struct {\n\t\tResult InitializeAssetsResponse `json:\"result\"`\n\t}\n\n\tif err := json.NewDecoder(resp.Body).Decode(&result); err != nil {\n\t\treturn nil, err\n\t}\n\n\tif result.Result.Jwt == \"\" {\n\t\treturn nil, fmt.Errorf(\"failed to initialize assets upload: no JWT received\")\n\t}\n\n\treturn &result.Result, nil\n}\n\nfunc (r *WorkerAssets) uploadAssets(manifest AssetManifest, directory, accountId, apiToken string, hashes []string, jwt string) (string, error) {","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/anomalyco/sst/blob/a0bd20f762883e72a35caccb4896c42ce5b3f707/pkg/server/resource/cloudflare-worker-assets.go#L178-L214","documentation":"uploadAssetManifest POSTs the asset manifest to Cloudflare's assets-upload-session endpoint and throws this error when the HTTP status is not 200. The response body is embedded in the message, so it carries Cloudflare's own error explanation (auth failure, bad script name, invalid manifest, rate limit, etc.).","triggerScenarios":"Any non-200 response from POST /accounts/{accountId}/workers/scripts/{scriptName}/assets-upload-session: 401/403 (bad or insufficient apiToken), 404 (scriptName does not exist), 400 (malformed manifest JSON), 429 (rate limited), 5xx (Cloudflare outage).","commonSituations":"API token missing Workers Scripts edit permission or expired; deploying assets before the Worker script was created; wrong accountId in config; manifest containing paths Cloudflare rejects; hitting Cloudflare during an incident or rate limit.","solutions":["Read the embedded HTTP status and response body in the error to identify Cloudflare's exact complaint.","Verify apiToken has 'Workers Scripts:Edit' permission and is valid for the target account.","Confirm the Worker script (scriptName) already exists in the given account before uploading assets.","Check accountId matches the account that owns the script.","If status is 429 or 5xx, retry after a short backoff."],"exampleFix":"// before\ncurl -X POST \"https://api.cloudflare.com/client/v4/accounts/$CF_ACCOUNT_ID/workers/scripts/my-worker/assets-upload-session\" \\\n  -H \"Authorization: Bearer $WRANGLER_TOKEN\" -d '{\"manifest\":{}}'\n// after: use a token scoped to the right account with Workers Scripts edit permission\nwrangler whoami  # confirm account + token scopes before deploying","handlingStrategy":"try-catch","validationCode":"// validate token + script before calling upload\nasync function preflight(accountId: string, scriptName: string, token: string) {\n  const res = await fetch(\n    `https://api.cloudflare.com/client/v4/accounts/${accountId}/workers/scripts/${scriptName}`,\n    { headers: { Authorization: `Bearer ${token}` } }\n  );\n  if (!res.ok) throw new Error(`preflight failed: HTTP ${res.status} ${await res.text()}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await deployAssets();\n} catch (e) {\n  const m = /HTTP (\\d+) /.match(String(e));\n  if (m && [429, 500, 502, 503].includes(+m[1])) {\n    await retryWithBackoff(deployAssets);\n  } else {\n    throw new Error(`Cloudflare rejected asset session: ${e.message} - check token scopes, accountId, and scriptName`);\n  }\n}","preventionTips":["Grant the API token 'Workers Scripts:Edit' on the correct account","Create the Worker script before uploading its assets","Double-check accountId and scriptName in config","Back off and retry on 429/5xx responses"],"tags":["cloudflare","api","http-error","authentication"],"backgroundTag":"cloudflare-api-http-error","analyzedSha":"a0bd20f762883e72a35caccb4896c42ce5b3f707","analyzedAt":"2026-08-30T11:26:00.383Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}