{"record":{"id":"9d43cc2a2bbfe87c","repo":"thanos-io/thanos","slug":"delete-s","errorCode":null,"errorMessage":"delete %s","messagePattern":"delete (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/block/block.go","lineNumber":215,"sourceCode":"// Delete removes directory that is meant to be block directory.\n// NOTE: Always prefer this method for deleting blocks.\n//   - We have to delete block's files in the certain order (meta.json first and deletion-mark.json last)\n//     to ensure we don't end up with malformed partial blocks. Thanos system handles well partial blocks\n//     only if they don't have meta.json. If meta.json is present Thanos assumes valid block.\n//   - This avoids deleting empty dir (whole bucket) by mistake.\nfunc Delete(ctx context.Context, logger log.Logger, bkt objstore.Bucket, id ulid.ULID) error {\n\tmetaFile := path.Join(id.String(), MetaFilename)\n\tdeletionMarkFile := path.Join(id.String(), metadata.DeletionMarkFilename)\n\n\t// Delete block meta file.\n\tok, err := bkt.Exists(ctx, metaFile)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"stat %s\", metaFile)\n\t}\n\n\tif ok {\n\t\tif err := bkt.Delete(ctx, metaFile); err != nil {\n\t\t\treturn errors.Wrapf(err, \"delete %s\", metaFile)\n\t\t}\n\t\tlevel.Debug(logger).Log(\"msg\", \"deleted file\", \"file\", metaFile, \"bucket\", bkt.Name())\n\t}\n\n\t// Delete the block objects, but skip:\n\t// - The metaFile as we just deleted. This is required for eventual object storages (list after write).\n\t// - The deletionMarkFile as we'll delete it at last.\n\terr = deleteDirRec(ctx, logger, bkt, id.String(), func(name string) bool {\n\t\treturn name == metaFile || name == deletionMarkFile\n\t})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Delete block deletion mark.\n\tok, err = bkt.Exists(ctx, deletionMarkFile)\n\tif err != nil {\n\t\treturn errors.Wrapf(err, \"stat %s\", deletionMarkFile)","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/block/block.go#L197-L233","documentation":"Delete (block directory removal) failed deleting an object from the bucket during recursive block deletion. Deletion order matters (meta.json first, deletion-mark.json last) to avoid malformed partial blocks, so failures abort the deletion.","triggerScenarios":"bkt.Delete on <ULID>/meta.json fails due to insufficient delete permissions, object-store errors, versioning/retention policies, or network failure.","commonSituations":"IAM policy allows read but not delete (common on shared buckets); S3 Object Lock / retention or soft-delete policies; bucket configured read-only for compactor; transient backend errors.","solutions":["Check bucket delete permissions","Retry after transient storage errors","Verify no retention policy blocks object deletion"],"exampleFix":"// before\nerr := block.Delete(ctx, logger, bkt, id)\n// after\nif err := block.Delete(ctx, logger, bkt, id); err != nil {\n    if isAccessDenied(err) { return fmt.Errorf(\"grant s3:DeleteObject on bucket: %w\", err) }\n    return err\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := block.Delete(ctx, logger, bkt, id); err != nil {\n    var denied interface{ AccessDenied() bool }\n    if strings.Contains(err.Error(), \"delete \") && isAccessDenied(err) {\n        return fmt.Errorf(\"bucket credentials lack delete permission: %w\", err)\n    }\n    return err\n}","preventionTips":["Grant s3:DeleteObject (or GCS storage.objects.delete) to the compactor identity","Disable/adjust Object Lock or retention rules on block buckets","Audit IAM policies when switching to shared/read-restricted buckets"],"tags":["object-storage","permissions","delete"],"backgroundTag":"permission-denied","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}