anomalyco/sst · error

failed to initialize assets upload: HTTP %d %s

Error message

failed to initialize assets upload: HTTP %d %s

What it means

Despite the message text, this is the general failure path for the Cloudflare PUT /accounts/{id}/workers/scripts/{name} API call in handleUpdate: any non-200 response is surfaced with the status code and response body. It covers auth failures, bad metadata/bindings, invalid script content, oversized uploads, and account/script name problems. Raised during Create and Update of the WorkerScript resource.

Source

Thrown at pkg/server/resource/cloudflare-worker-script.go:223

	req, err := http.NewRequest("PUT", url, &body)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "multipart/form-data; boundary="+writer.Boundary())
	req.Header.Set("Authorization", "Bearer "+input.ApiToken)

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	// print out response body as a string
	if resp.StatusCode != http.StatusOK {
		responseBody, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("failed to initialize assets upload: HTTP %d %s", resp.StatusCode, string(responseBody))
	}
	return nil
}

func buildMetadata(input *WorkerScriptInputs) map[string]interface{} {
	metadata := make(map[string]interface{})

	// Assets
	if input.Assets.Jwt != "" || input.Assets.Config.Headers != "" || input.Assets.Config.Redirects != "" || input.Assets.Config.HtmlHandling != "" || input.Assets.Config.NotFoundHandling != "" || input.Assets.Config.RunWorkerFirst {
		assets := make(map[string]interface{})
		if input.Assets.Jwt != "" {
			assets["jwt"] = input.Assets.Jwt
		}
		config := make(map[string]interface{})
		if input.Assets.Config.Headers != "" {
			config["_headers"] = input.Assets.Config.Headers
		}
		if input.Assets.Config.Redirects != "" {

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Read the response body in the error — Cloudflare includes an errors[] array with codes explaining the rejection
  2. Verify apiToken is valid and has Workers Scripts:Edit permission for the account
  3. Confirm accountId and scriptName are correct and the script exists if updating
  4. If using ES modules, ensure mainModule is set in inputs
  5. Retry on 5xx; fix inputs on 4xx

Example fix

// before: mainModule empty for an ES module worker
{"content": {...}}
// after: set mainModule so content-type becomes application/javascript+module
{"content": {...}, "mainModule": "index.js", "compatibilityDate": "2024-01-01"}
Defensive patterns

Strategy: retry

Validate before calling

if input.AccountId == "" || input.ScriptName == "" { return errors.New("accountId and scriptName are required") }
if input.ApiToken == "" { return errors.New("apiToken is required") }
if input.MainModule == "" { log.Println("warning: uploading as classic script (application/javascript)") }

Try / catch

var netErr net.Error
if errors.As(err, &netErr) || strings.Contains(err.Error(), "HTTP 5") || strings.Contains(err.Error(), "HTTP 429") {
    // retry with backoff
} else if strings.Contains(err.Error(), "HTTP 4") {
    // do not retry; fix token/inputs using the response body
}

Prevention

When it happens

Trigger: client.Do succeeds but resp.StatusCode != 200 on PUT https://api.cloudflare.com/client/v4/accounts/{AccountId}/workers/scripts/{ScriptName}; common statuses: 403 (invalid/insufficient apiToken), 400 (bad metadata, invalid bindings, missing mainModule), 404 (wrong accountId), 413 (script too large).

Common situations: Expired or wrongly-scoped Cloudflare API token; wrong accountId or scriptName; ES module worker uploaded without mainModule set; compatibility date/flags rejected; script exceeding size limits; transient Cloudflare 5xx.

Related errors


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