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

  1. Treat 'object not found' as success in most cleanup flows — log it at warning level instead of failing
  2. 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
  3. Check BasePath/prefix config hasn't changed since the objects were uploaded
  4. 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

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


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/51beff41a8a93dc0. Report an issue: GitHub.