anomalyco/sst · error

failed to write encoded content for %s: %w

Error message

failed to write encoded content for %s: %w

What it means

After creating the form part, uploadAssets writes the base64-encoded asset content into it. This error wraps a write failure on the multipart writer; since the underlying writer is an in-memory bytes.Buffer, it only fails on extremely rare internal multipart errors (e.g. writing after the writer was closed or a corrupted part).

Source

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

		if err != nil {
			return "", fmt.Errorf("failed to read file %s: %w", absFilePath, err)
		}
		
		// Base64 encode the file content
		encodedContent := base64.StdEncoding.EncodeToString(fileContent)
		
		// Create form field with content type header
		part, err := writer.CreatePart(map[string][]string{
			"Content-Disposition": []string{fmt.Sprintf(`form-data; name="%s"; filename="%s"`, hash, hash)},
			"Content-Type":        []string{contentType},
		})
		if err != nil {
			return "", fmt.Errorf("failed to create form part %s: %w", hash, err)
		}

		_, err = part.Write([]byte(encodedContent))
		if err != nil {
			return "", fmt.Errorf("failed to write encoded content for %s: %w", hash, err)
		}
	}
	err := writer.Close()
	if err != nil {
		return "", fmt.Errorf("failed to close writer: %w", err)
	}

	url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%s/workers/assets/upload?base64=true", accountId)

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

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Ensure no code path closes the writer before all parts are written
  2. Check errors.Unwrap(err) for the underlying cause
  3. Write to a fresh bytes.Buffer/multipart.Writer for this upload
  4. If contents can be huge, stream to a temp file instead of an in-memory buffer

Example fix

// before
var body bytes.Buffer
writer := multipart.NewWriter(&body)
// ... later reuse after Close() ...
_, err = part.Write([]byte(encodedContent))
// after
var body bytes.Buffer
writer := multipart.NewWriter(&body)
// write ALL parts, then Close() exactly once at the end
_, err = part.Write([]byte(encodedContent))
if err != nil {
	return "", fmt.Errorf("failed to write encoded content for %s: %w", hash, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if body.Len() > maxInMemoryBodySize {
	return fmt.Errorf("asset upload body too large for in-memory buffer")
}

Try / catch

if _, err := part.Write([]byte(encodedContent)); err != nil {
	return "", fmt.Errorf("failed to write encoded content for %s: %w", hash, err)
}

Prevention

When it happens

Trigger: part.Write([]byte(encodedContent)) returns non-nil err inside the asset loop in uploadAssets (pkg/server/resource/cloudflare-worker-assets.go:254); practically only when the multipart.Writer is in an invalid state (closed early, buffer exhausted/failed).

Common situations: Reusing or closing the multipart writer before all parts are written; memory pressure causing buffer failures in constrained environments.

Related errors


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