@@ -14,10 +14,12 @@ import (
1414
1515 "github.com/buildbuddy-io/buildbuddy/server/interfaces"
1616 "github.com/buildbuddy-io/buildbuddy/server/remote_cache/digest"
17+ "github.com/buildbuddy-io/buildbuddy/server/util/log"
1718 "github.com/buildbuddy-io/buildbuddy/server/util/proto"
1819 "github.com/buildbuddy-io/buildbuddy/server/util/status"
1920 "github.com/buildbuddy-io/fastcdc2020/fastcdc"
2021 "golang.org/x/sync/errgroup"
22+ gstatus "google.golang.org/grpc/status"
2123
2224 repb "github.com/buildbuddy-io/buildbuddy/proto/remote_execution"
2325 rspb "github.com/buildbuddy-io/buildbuddy/proto/resource"
@@ -270,7 +272,14 @@ func (cm *Manifest) Store(ctx context.Context, cache interfaces.Cache) error {
270272 return err
271273 }
272274
273- return cache .Set (ctx , acRNProto , arBytes )
275+ if err := cache .Set (ctx , acRNProto , arBytes ); err != nil {
276+ err = sanitizeManifestError (err , acRNProto .GetDigest ().GetHash (), cm .BlobDigest .GetHash ())
277+ if status .IsInternalError (err ) {
278+ log .CtxInfof (ctx , "Failed to set chunking manifest (blob %s, manifest key %s): %v" , cm .BlobDigest .GetHash (), acRNProto .GetDigest ().GetHash (), err )
279+ }
280+ return err
281+ }
282+ return nil
274283}
275284
276285// LoadManifest retrieves a chunked manifest from the cache. It does NOT validate existence of the chunks.
@@ -282,6 +291,10 @@ func LoadManifest(ctx context.Context, cache interfaces.Cache, blobDigest *repb.
282291
283292 arBytes , err := cache .Get (ctx , acRNProto )
284293 if err != nil {
294+ err = sanitizeManifestError (err , acRNProto .GetDigest ().GetHash (), blobDigest .GetHash ())
295+ if status .IsInternalError (err ) {
296+ log .CtxInfof (ctx , "Failed to get chunking manifest (blob %s, manifest key %s): %v" , blobDigest .GetHash (), acRNProto .GetDigest ().GetHash (), err )
297+ }
285298 if status .IsNotFoundError (err ) {
286299 blobRN := digest .NewCASResourceName (blobDigest , instanceName , digestFunction ).ToProto ()
287300 if exists , existsErr := cache .Contains (ctx , blobRN ); existsErr != nil {
@@ -385,6 +398,28 @@ func acResourceName(blobDigest *repb.Digest, instanceName string, digestFunction
385398 return acRN .ToProto (), nil
386399}
387400
401+ // sanitizeManifestError replaces the salted AC key hash with the original blob hash in
402+ // the error message, so callers see the blob digest rather than the internal salted key.
403+ // The gRPC status code is preserved.
404+ func sanitizeManifestError (err error , saltedHash , blobHash string ) error {
405+ if err == nil || saltedHash == "" || saltedHash == blobHash {
406+ return err
407+ }
408+ grpcStatus , ok := gstatus .FromError (err )
409+ if ! ok {
410+ return fmt .Errorf ("%s" , sanitizeMsg (err .Error (), saltedHash , blobHash ))
411+ }
412+ return gstatus .Error (grpcStatus .Code (), sanitizeMsg (grpcStatus .Message (), saltedHash , blobHash ))
413+ }
414+
415+ func sanitizeMsg (msg , saltedHash , blobHash string ) string {
416+ replacement := fmt .Sprintf ("manifestKey(%s)" , blobHash )
417+ if replaced := strings .ReplaceAll (msg , saltedHash , replacement ); replaced != msg {
418+ return replaced
419+ }
420+ return fmt .Sprintf ("%s (blob %s)" , msg , blobHash )
421+ }
422+
388423func DigestsSummary (digests []* repb.Digest ) string {
389424 const maxShown = 3
390425 strs := digestsStrings (digests ... )
0 commit comments