apache/beam · error

staged artifact for has invalid SHA256: , want

Error message

staged artifact for %v has invalid SHA256: %v, want %v

What it means

matchLocations compares the staged blob's computed SHA256 against the manifest's declared SHA256. On mismatch the staged content differs from what the manifest expects, so it refuses to emit a location for that artifact.

Solutions

  1. Rebuild the manifest from the current artifact files so declared SHA256 values match
  2. Re-stage the artifact via PutArtifact so the staged blob matches the manifest hash
  3. Verify the artifact file wasn't modified between manifest creation and staging

Example fix

// before: stale manifest hash
manifest.Sha256 = "aaa..." // file rebuilt since

// after: regenerate manifest from current files
manifest.Sha256 = computeSHA256(artifactPath)
Defensive patterns

Strategy: validation

Validate before calling

sum := sha256.Sum256(artifactBytes)
if a.Sha256 != "" && hex.EncodeToString(sum[:]) != a.Sha256 {
    return fmt.Errorf("artifact %q hash mismatch before commit", a.Name)
}

Try / catch

if err := CommitManifest(ctx, req); err != nil {
    if strings.Contains(err.Error(), "invalid SHA256") {
        // regenerate manifest hashes and re-stage
    }
    return err
}

Prevention

When it happens

Trigger: Calling CommitManifest when an artifact's declared a.Sha256 (non-empty) differs from the hash of the bytes actually uploaded via PutArtifact for the same name.

Common situations: Artifact file was modified/rebuilt between manifest generation and staging; corrupt upload; re-uploading different content under the same artifact name.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

	// jobs. Such a server would also use the ID sent with each request.

	return &jobpb.CommitManifestResponse{RetrievalToken: gcsx.MakeObject(s.bucket, s.manifest)}, nil
}

// matchLocations ensures that all artifacts have been staged and have valid
// content. It is fine for staged artifacts to not appear in the manifest.
func matchLocations(artifacts []*jobpb.ArtifactMetadata, blobs map[string]staged) ([]*jobpb.ProxyManifest_Location, error) {
	var loc []*jobpb.ProxyManifest_Location
	for _, a := range artifacts {
		info, ok := blobs[a.Name]
		if !ok {
			return nil, errors.Errorf("artifact %v not staged", a.Name)
		}
		if a.Sha256 == "" {
			a.Sha256 = info.hash
		}
		if info.hash != a.Sha256 {
			return nil, errors.Errorf("staged artifact for %v has invalid SHA256: %v, want %v", a.Name, info.hash, a.Sha256)
		}

		loc = append(loc, &jobpb.ProxyManifest_Location{Name: a.Name, Uri: info.object})
	}
	return loc, nil
}

// PutArtifact stores the given artifact in GCS.
func (s *StagingServer) PutArtifact(ps jobpb.LegacyArtifactStagingService_PutArtifactServer) error {
	// Read header

	header, err := ps.Recv()
	if err != nil {
		return errors.Wrap(err, "failed to receive header")
	}
	md := header.GetMetadata().GetMetadata()
	if md == nil {
		return errors.Errorf("expected header as first message: %v", header)

View on GitHub (pinned to 12126d8942)