anomalyco/sst · error

failed to create form part

Error message

failed to create form part %s: %w

What it means

This error wraps a failure from mime/multipart.Writer.CreatePart while building the multipart body used to PUT a Worker script to the Cloudflare API. CreatePart only fails if the multipart writer was already closed or the underlying buffer cannot accept a new part header, so it is nearly always a programming/lifecycle bug rather than a user input problem. It is returned by handleUpdate, which backs both Create and Update of the WorkerScript resource.

Solutions

  1. Check that no code path calls writer.Close() before this CreatePart call; all CreatePart/Write calls must precede Close
  2. Re-run the deploy — this is deterministic, so if it persists inspect custom modifications to cloudflare-worker-script.go
  3. Report upstream with the wrapped inner error (%w) if it occurs on an unmodified checkout

Example fix

// before
err = writer.Close()
contentPart, err := writer.CreatePart(headers) // fails: writer closed
// after
contentPart, err := writer.CreatePart(headers)
// ... write all parts ...
err = writer.Close()
Defensive patterns

Strategy: try-catch

Validate before calling

if input.Content.Hash == "" { return errors.New("content hash required before upload") }

Try / catch

err := r.handleUpdate(input)
if err != nil {
    var wrap *fmt.wrapError
    if errors.As(err, &wrap) { log.Printf("multipart failure: %v", wrap.Unwrap()) }
    return err
}

Prevention

When it happens

Trigger: writer.CreatePart returns an error while creating the content part for input.Content.Hash — practically only when the multipart.Writer has already been Close()d, or an I/O error occurs writing headers into the underlying bytes.Buffer.

Common situations: Reordering the handleUpdate body so writer.Close() is called before CreatePart; writing additional parts after Close; an out-of-memory or closed-buffer condition making the bytes.Buffer write fail.

Related errors


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

Appendix: source

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

	// Add file content to form data
	fileContent, err := os.ReadFile(input.Content.Filename)
	if err != nil {
		return fmt.Errorf("failed to read file %s: %w", input.Content.Filename, err)
	}

	contentType := "application/javascript"
	if input.MainModule != "" {
		input.MainModule = input.Content.Hash
		contentType = "application/javascript+module"
	}

	contentPart, err := writer.CreatePart(map[string][]string{
		"Content-Disposition": []string{fmt.Sprintf(`form-data; name="%s"; filename="%s"`, input.Content.Hash, input.Content.Hash)},
		"Content-Type":        []string{contentType},
	})
	if err != nil {
		return fmt.Errorf("failed to create form part %s: %w", input.Content.Hash, err)
	}

	_, err = contentPart.Write([]byte(fileContent))
	if err != nil {
		return fmt.Errorf("failed to write file content for %s: %w", input.Content.Hash, err)
	}

	// Add metadata to form data
	metadataPart, err := writer.CreatePart(map[string][]string{
		"Content-Disposition": []string{`form-data; name="metadata"`},
		"Content-Type":        []string{"application/json"},
	})
	if err != nil {
		return fmt.Errorf("failed to create form part metadata: %w", err)
	}

	metadata, err := json.Marshal(buildMetadata(input))
	if err != nil {

View on GitHub (pinned to a0bd20f762)