flipped-aurora/gin-vue-admin · warning

unknown error

Error message

unknown error

What it means

Not an SDK failure: this is the code path in AwsS3.DeleteFiles that iterates out.Errors (per-key delete failures returned inside a successful DeleteObjects response). For each failed key it builds an error message; when the S3 response omits the Message field, the code defaults to the literal string 'unknown error'. It indicates specific objects in the batch could not be deleted (typically AccessDenied or NoSuchKey-style conditions reported per key).

Source

Thrown at server/utils/upload/aws_s3.go:160

		Delete: &types.Delete{
			Objects: objects,
			Quiet:   aws.Bool(true),
		},
	})
	if err != nil {
		return nil, errors.New("function client.DeleteObjects() failed, err:" + err.Error())
	}

	for _, e := range out.Errors {
		key := ""
		if e.Key != nil {
			key = *e.Key
		}
		msg := "unknown error"
		if e.Message != nil {
			msg = *e.Message
		}
		failed = append(failed, DeleteFailure{Key: key, Err: errors.New(msg)})
	}
	return failed, nil
}

// ListFiles 按前缀列举存储对象,cursor 映射到 ContinuationToken。
func (*AwsS3) ListFiles(ctx context.Context, prefix, cursor string, limit int) (files []FileInfo, nextCursor string, hasMore bool, err error) {
	client, err := newS3Client()
	if err != nil {
		return nil, "", false, err
	}
	bucket := global.GVA_CONFIG.AwsS3.Bucket

	if limit <= 0 {
		limit = 100
	}

	input := &s3.ListObjectsV2Input{
		Bucket:  aws.String(bucket),

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Inspect the returned []DeleteFailure entries: collect keys and retry/only handle genuinely failed ones instead of failing the whole batch
  2. Compare the failing keys' prefixes with the IAM policy scope and widen or correct s3:DeleteObject resource ARNs
  3. Check bucket settings (Object Lock, versioning, deny policies) that block deletion of the affected keys
  4. Log both Key and message from DeleteFailure to diagnose; if messages are empty ('unknown error'), enable SDK client-side logging to capture the raw XML

Example fix

// before
failed = append(failed, DeleteFailure{Key: key, Err: errors.New(msg)}) // caller may ignore
// after
for _, f := range failed {
    logger.WithCtx(ctx).Mod("upload").Warn("bulk delete key failed", zap.String("key", f.Key), zap.Error(f.Err))
}
if len(failed) > 0 { return failed, nil } // partial success is expected; surface it
Defensive patterns

Strategy: fallback

Validate before calling

// scope-check before batch delete
allowedPrefix := "public/"
for _, k := range keys {
    if !strings.HasPrefix(k, allowedPrefix) {
        return fmt.Errorf("key %q outside permitted prefix %q, would be AccessDenied", k, allowedPrefix)
    }
}

Type guard

func hasRealFailures(failed []upload.DeleteFailure) bool {
    for _, f := range failed {
        if f.Err != nil && f.Err.Error() != "unknown error" { return true }
    }
    return false
}

Try / catch

failed, err := s3Store.DeleteFiles(keys)
if err != nil { return err }
if len(failed) > 0 {
    for _, f := range failed {
        logger.Warn("partial delete failure", zap.String("key", f.Key), zap.Error(f.Err))
    }
    // fallback: retry failed keys individually with single DeleteObject
    for _, f := range failed { _ = s3Store.DeleteFile(f.Key) }
}

Prevention

When it happens

Trigger: Calling DeleteFiles where some keys in the batch fail individually: the IAM policy allows the bucket but not the specific key prefix, the key is protected by a bucket policy/Object Lock/versioning setting, or S3 returns an error entry with no message text populated.

Common situations: Prefix-scoped IAM policies (allow s3:DeleteObject on public/* only) while deleting keys outside that prefix; S3 Object Lock or versioned buckets preventing hard deletes; partially authorized multi-tenant prefixes; S3-compatible stores that omit the Message field in error entries.

Related errors


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