flipped-aurora/gin-vue-admin · warning
对象未被删除
Error message
对象未被删除
What it means
Not an SDK error: AliyunOSS.DeleteFiles (server/utils/upload/aliyun_oss.go:121) compares the requested keys against result.DeletedObjects returned by OSS (non-quiet mode) and wraps any key absent from the deleted list in a DeleteFailure{Key, Err:"对象未被删除"}. The batch call succeeded; specific objects simply were not reported as deleted. Since OSS delete of a missing key normally succeeds, absence from the list usually means the key never existed, already had no version to delete, or a key-name mismatch (case, encoding, prefix).
Source
Thrown at server/utils/upload/aliyun_oss.go:121
return nil, errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error())
}
result, err := bucket.DeleteObjects(keys)
if err != nil {
logger.WithCtx(ctx).Mod("upload").Err(err).Error("function bucket.DeleteObjects() failed")
return nil, errors.New("function bucket.DeleteObjects() failed, err:" + err.Error())
}
// 默认非 quiet 模式,OSS 会返回已删除的 key 列表,与之对比找出未删项。
deleted := make(map[string]struct{}, len(result.DeletedObjects))
for _, k := range result.DeletedObjects {
deleted[k] = struct{}{}
}
failed := make([]DeleteFailure, 0)
for _, key := range keys {
if _, ok := deleted[key]; !ok {
failed = append(failed, DeleteFailure{Key: key, Err: errors.New("对象未被删除")})
}
}
return failed, nil
}
// ListFiles 按前缀列举对象,cursor 映射为 OSS 的 marker。
func (*AliyunOSS) ListFiles(ctx context.Context, prefix, cursor string, limit int) ([]FileInfo, string, bool, error) {
if limit <= 0 {
limit = 100
}
bucket, err := NewBucket()
if err != nil {
logger.WithCtx(ctx).Mod("upload").Err(err).Error("function AliyunOSS.NewBucket() Failed")
return nil, "", false, errors.New("function AliyunOSS.NewBucket() Failed, err:" + err.Error())
}
result, err := bucket.ListObjects(oss.Prefix(prefix), oss.Marker(cursor), oss.MaxKeys(limit))View on GitHub (pinned to 3136500ef3)
Solutions
- Treat 'object not found' as success in most cleanup flows — log it at warning level instead of failing
- Verify the exact key exists first with bucket.IsObjectExist or ListObjects with the key as prefix; compare byte-for-byte with what's stored in DB
- Check BasePath/prefix config hasn't changed since the objects were uploaded
- Note: in quiet mode OSS returns no DeletedObjects at all — confirm the SDK call is not using oss.DeleteObjectsQuiet(true), which would make every key look 'not deleted'
Example fix
// before
if _, ok := deleted[key]; !ok {
failed = append(failed, DeleteFailure{Key: key, Err: errors.New("对象未被删除")})
}
// after: distinguish missing-object (benign) from real failures
if _, ok := deleted[key]; !ok {
exist, _ := bucket.IsObjectExist(key)
if !exist {
logger.Warn("object already absent, treating as deleted", key)
continue
}
failed = append(failed, DeleteFailure{Key: key, Err: errors.New("对象未被删除")})
} Defensive patterns
Strategy: fallback
Validate before calling
// before deleting, confirm keys actually exist
for _, key := range keys {
ok, err := bucket.IsObjectExist(key)
if err != nil {
return err
}
if !ok {
logger.Warnf("skip delete, key not in bucket: %s", key)
}
} Type guard
func isBenignMissingKey(f DeleteFailure) bool {
return f.Err != nil && f.Err.Error() == "对象未被删除"
} Try / catch
failed, err := uploadSvc.DeleteFiles(ctx, keys)
if err != nil {
return fmt.Errorf("batch delete call failed: %w", err)
}
for _, f := range failed {
if isBenignMissingKey(f) {
logger.Warnf("key already absent, ignoring: %s", f.Key)
continue
}
// surface genuinely stuck keys for manual review
logger.Errorf("delete reported failure for %s: %v", f.Key, f.Err)
} Prevention
- Treat delete-of-missing-key as success — OSS deletes are idempotent by design
- Recompute keys from current BasePath config rather than stale stored URLs
- Remember keys are case-sensitive and stored byte-for-byte; normalize once at upload time
- Do not enable quiet mode if you rely on DeletedObjects for the missing-key comparison
When it happens
Trigger: Deleting keys that don't exist in the bucket (wrong prefix, wrong BasePath baked into the key), key case/special-character encoding differing from what's stored, or keys deleted concurrently by another process/job between listing and deletion.
Common situations: Cleanup routines built from stale DB paths after the bucket was purged or BasePath config changed, double-delete of the same upload, case-sensitive key mismatches (OSS keys are case-sensitive), URL-encoded keys passed unencoded or vice versa.
Related errors
- function bucket.IsObjectExist() failed, err:
- function bucket.DeleteObjects() failed, err:
- function bucket.ListObjects() failed, err:
- function client.ListObjectsV2() failed, err:
- function file.Open() failed, err:
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/51beff41a8a93dc0.
Report an issue: GitHub.