apache/beam · error

failed to stage artifact

Error message

failed to stage artifact %v

What it means

Error returned by PutArtifact in the GCS artifact staging proxy when gcsx.WriteObject fails while streaming artifact content to the bucket under s.root. The underlying GCS client/write error is wrapped; because object writes are atomic, a failed write leaves no partial object, but the artifact was not staged and staging must be retried or diagnosed.

Solutions

  1. Check the wrapped error for the underlying cause (permissions, bucket name, stream EOF)
  2. Verify s.bucket is correct and writable by the service account
  3. Retry the PutArtifact call; ensure the client keeps the stream open for the whole upload
Defensive patterns

Strategy: retry

Validate before calling

// pre-check bucket writability
it := client.Bucket(bucket).Objects(ctx, nil)
_, err := it.Next() // confirms bucket exists/access

Try / catch

if err := stream.PutArtifact(ctx); err != nil && strings.Contains(err.Error(), "failed to stage artifact") {
    // inspect wrapped cause; fix bucket/permissions or retry upload
}

Prevention

When it happens

Trigger: GCS write fails: bucket doesn't exist or lacks write permission; reader (client stream) errors mid-upload; context cancelled during transfer.

Common situations: Wrong bucket configured on StagingServer; client disconnects mid-upload causing reader error; GCS rate limits or quota exhaustion during large uploads.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/cad733b3963a130f. Report an issue: GitHub.

Appendix: source

Thrown at sdks/go/pkg/beam/artifact/gcsproxy/staging.go:145

	}
	md := header.GetMetadata().GetMetadata()
	if md == nil {
		return errors.Errorf("expected header as first message: %v", header)
	}
	object := path.Join(s.root, md.Name)

	// Stream content to GCS. We don't have to worry about partial
	// or abandoned writes, because object writes are atomic.

	ctx := ps.Context()
	cl, err := gcsx.NewClient(ctx, storage.ScopeReadWrite)
	if err != nil {
		return errors.Wrap(err, "failed to create GCS client")
	}

	r := &reader{sha256W: sha256.New(), stream: ps}
	if err := gcsx.WriteObject(ctx, cl, s.bucket, object, r); err != nil {
		return errors.Wrapf(err, "failed to stage artifact %v", md.Name)
	}
	hash := r.SHA256()
	if md.Sha256 != "" && md.Sha256 != hash {
		return errors.Errorf("invalid SHA256 for artifact %v: %v want %v", md.Name, hash, md.Sha256)
	}

	s.mu.Lock()
	s.blobs[md.Name] = staged{object: gcsx.MakeObject(s.bucket, object), hash: hash}
	s.mu.Unlock()

	return ps.SendAndClose(&jobpb.PutArtifactResponse{})
}

// reader is an adapter between the artifact stream and the GCS stream reader.
// It also computes the SHA256 of the content.
type reader struct {
	sha256W hash.Hash
	buf     []byte

View on GitHub (pinned to 12126d8942)