{"record":{"id":"b0324480a78aca9f","repo":"kopia/kopia","slug":"getcontent","errorCode":null,"errorMessage":"getContent","messagePattern":"getContent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"repo/content/indexblob/index_blob_encryption.go","lineNumber":97,"sourceCode":"\n// EncryptionManager manages encryption and caching of index blobs.\ntype EncryptionManager struct {\n\tst             blob.Storage\n\tcrypter        blobcrypto.Crypter\n\tindexBlobCache *cache.PersistentCache\n\tlog            *contentlog.Logger\n}\n\n// GetEncryptedBlob fetches and decrypts the contents of a given encrypted blob\n// using cache first and falling back to the underlying storage.\nfunc (m *EncryptionManager) GetEncryptedBlob(ctx context.Context, blobID blob.ID, output *gather.WriteBuffer) error {\n\tvar payload gather.WriteBuffer\n\tdefer payload.Close()\n\n\tif err := m.indexBlobCache.GetOrLoad(ctx, string(blobID), func(output *gather.WriteBuffer) error {\n\t\treturn m.st.GetBlob(ctx, blobID, 0, -1, output)\n\t}, &payload); err != nil {\n\t\treturn errors.Wrap(err, \"getContent\")\n\t}\n\n\treturn errors.Wrap(blobcrypto.Decrypt(m.crypter, payload.Bytes(), blobID, output), \"decrypt blob\")\n}\n\n// EncryptAndWriteBlob encrypts and writes the provided data into a blob,\n// with name {prefix}{hash}[-{suffix}].\nfunc (m *EncryptionManager) EncryptAndWriteBlob(ctx context.Context, data gather.Bytes, prefix, suffix blob.ID) (blob.Metadata, error) {\n\tvar data2 gather.WriteBuffer\n\tdefer data2.Close()\n\n\tblobID, err := blobcrypto.Encrypt(m.crypter, data, prefix, suffix, &data2)\n\tif err != nil {\n\t\treturn blob.Metadata{}, errors.Wrap(err, \"error encrypting\")\n\t}\n\n\tt0 := timetrack.StartTimer()\n","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/repo/content/indexblob/index_blob_encryption.go#L79-L115","documentation":"EncryptionManager.GetEncryptedBlob fetches the raw index blob through an in-memory cache (indexBlobCache.GetOrLoad) whose loader calls st.GetBlob to read the full blob. Any failure from the cache or underlying storage GetBlob is wrapped as \"getContent\". The name reflects the legacy internal loader function that retrieves the (still encrypted) blob content.","triggerScenarios":"Calling GetEncryptedBlob when the blob does not exist in storage, the storage backend errors, or the cache loader's st.GetBlob call fails for the given blobID.","commonSituations":"Blob already garbage-collected by cleanup while an index still references it; network/auth failures to object storage; wrong object ID passed by compaction-log or cleanup entry processing.","solutions":["Check the wrapped cause for blob-not-found: if the blob was deleted by cleanup, the referencing index metadata is stale — refresh/compact it.","Verify the blobID exists in storage (list blobs with the same prefix) and that credentials/network to the backend work.","Retry transient storage errors; the cache loader will re-attempt st.GetBlob.","If caused by cleanup racing compaction, tune cleanup delay or re-register the index blobs."],"exampleFix":"// before\npayload, err := mgr.GetEncryptedBlob(ctx, blobID) // blob may be deleted\n// after\npayload, err := mgr.GetEncryptedBlob(ctx, blobID)\nif err != nil && blob.ErrBlobNotFound.Is(err) {\n\treturn refreshIndexAndRetry(ctx, blobID)\n}","handlingStrategy":"try-catch","validationCode":"md, err := st.GetMetadata(ctx, blobID)\nexists := err == nil","typeGuard":null,"tryCatchPattern":"payload, err := mgr.GetEncryptedBlob(ctx, blobID)\nif err != nil {\n\tif blob.IsBlobNotFound(err) {\n\t\t// refresh index metadata or re-compact; blob was cleaned up\n\t}\n\treturn err\n}","preventionTips":["Check blob existence (GetMetadata) before expecting to read index blobs.","Tune cleanup delay so referenced index blobs are not garbage-collected during reads.","Handle transient storage/network errors with retries."],"tags":["storage","blob","cache","network"],"backgroundTag":"resource-not-found","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}