{"record":{"id":"fae140a6bd7c4b59","repo":"apache/beam","slug":"artifact-v-not-staged","errorCode":null,"errorMessage":"artifact %v not staged","messagePattern":"artifact (.+?) not staged","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/artifact/gcsproxy/staging.go","lineNumber":106,"sourceCode":"\t\treturn nil, errors.Wrap(err, \"failed to write manifest\")\n\t}\n\n\t// Commit returns the location of the manifest as the token, which can\n\t// then be used to configure the retrieval proxy. It is redundant right\n\t// now, but would be needed for a staging server that serves multiple\n\t// jobs. Such a server would also use the ID sent with each request.\n\n\treturn &jobpb.CommitManifestResponse{RetrievalToken: gcsx.MakeObject(s.bucket, s.manifest)}, nil\n}\n\n// matchLocations ensures that all artifacts have been staged and have valid\n// content. It is fine for staged artifacts to not appear in the manifest.\nfunc matchLocations(artifacts []*jobpb.ArtifactMetadata, blobs map[string]staged) ([]*jobpb.ProxyManifest_Location, error) {\n\tvar loc []*jobpb.ProxyManifest_Location\n\tfor _, a := range artifacts {\n\t\tinfo, ok := blobs[a.Name]\n\t\tif !ok {\n\t\t\treturn nil, errors.Errorf(\"artifact %v not staged\", a.Name)\n\t\t}\n\t\tif a.Sha256 == \"\" {\n\t\t\ta.Sha256 = info.hash\n\t\t}\n\t\tif info.hash != a.Sha256 {\n\t\t\treturn nil, errors.Errorf(\"staged artifact for %v has invalid SHA256: %v, want %v\", a.Name, info.hash, a.Sha256)\n\t\t}\n\n\t\tloc = append(loc, &jobpb.ProxyManifest_Location{Name: a.Name, Uri: info.object})\n\t}\n\treturn loc, nil\n}\n\n// PutArtifact stores the given artifact in GCS.\nfunc (s *StagingServer) PutArtifact(ps jobpb.LegacyArtifactStagingService_PutArtifactServer) error {\n\t// Read header\n\n\theader, err := ps.Recv()","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/artifact/gcsproxy/staging.go#L88-L124","documentation":"matchLocations verifies that every artifact listed in the job manifest has a corresponding blob already staged in GCS. If an artifact name is absent from the staging server's blob map, it cannot produce a ProxyManifest location, so it fails fast with this error. CommitManifest calls it when finalizing the staged manifest.","triggerScenarios":"Calling CommitManifest when the manifest references an artifact whose name was never staged via PutArtifact on this StagingServer, or after the staging server was restarted losing in-memory blob state.","commonSituations":"Job submitted referencing artifacts staged by a different worker; StagingServer restarted between PutArtifact and CommitManifest; artifact names in the manifest don't match names used at staging time (typos, path prefix differences).","solutions":["Stage all manifest artifacts via PutArtifact on the same StagingServer instance before calling CommitManifest","Verify artifact names in the manifest exactly match md.Name values sent during PutArtifact","If the server restarts, re-stage the artifacts before committing the manifest"],"exampleFix":"// before: committing manifest without staging\nproxy.CommitManifest(ctx, artifacts) // artifact 'foo.jar' never staged\n\n// after: stage first, then commit\nfor _, a := range toStage { stream.PutArtifact(ctx, a) }\nproxy.CommitManifest(ctx, artifacts)","handlingStrategy":"validation","validationCode":"// before CommitManifest\nfor _, a := range artifacts {\n    if _, ok := serverBlobs[a.Name]; !ok {\n        return fmt.Errorf(\"artifact %q missing; stage it via PutArtifact first\", a.Name)\n    }\n}","typeGuard":"func isStaged(name string, blobs map[string]staged) bool { _, ok := blobs[name]; return ok }","tryCatchPattern":"if err := CommitManifest(ctx, req); err != nil {\n    if strings.Contains(err.Error(), \"not staged\") {\n        // re-stage the artifact, then retry commit\n    }\n    return err\n}","preventionTips":["Stage every manifest artifact on the same server instance before committing","Keep artifact names consistent between staging and manifest generation","Avoid restarting the StagingServer between staging and commit"],"tags":["gcs","artifact-staging","manifest","state"],"backgroundTag":"record-not-found","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}