{"record":{"id":"89ad808f5d783128","repo":"Tencent/WeKnora","slug":"failed-to-delete-file-from-ks3-w","errorCode":null,"errorMessage":"failed to delete file from KS3: %w","messagePattern":"failed to delete file from KS3: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/file/ks3.go","lineNumber":251,"sourceCode":"\n\treturn resp.Body, nil\n}\n\nfunc (s *ks3FileService) DeleteFile(ctx context.Context, filePath string) error {\n\t_, objectKey, err := parseKS3FilePath(filePath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif err := utils.SafeObjectKey(objectKey); err != nil {\n\t\treturn fmt.Errorf(\"invalid file path: %w\", err)\n\t}\n\n\t_, err = s.client.DeleteObject(&ks3s3.DeleteObjectInput{\n\t\tBucket: ks3aws.String(s.bucketName),\n\t\tKey:    ks3aws.String(objectKey),\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to delete file from KS3: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (s *ks3FileService) CheckConnectivity(ctx context.Context) error {\n\tdone := make(chan error, 1)\n\tgo func() {\n\t\t_, err := s.client.HeadBucket(&ks3s3.HeadBucketInput{\n\t\t\tBucket: ks3aws.String(s.bucketName),\n\t\t})\n\t\tdone <- err\n\t}()\n\tselect {\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\tcase err := <-done:\n\t\treturn err\n\t}","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/file/ks3.go#L233-L269","documentation":"ks3FileService.DeleteFile wraps DeleteObject SDK errors with \"failed to delete file from KS3: %w\". The key was valid but the remote delete failed — permissions, missing object (some configs), connectivity, or bucket mismatch. Note KS3/S3 DeleteObject often succeeds silently on missing keys, so this usually means permission or network trouble.","triggerScenarios":"DeleteObject returns an error: AK/SK lacks s3:DeleteObject permission, bucket in path differs from configured bucket, endpoint/region wrong, network failure after retries.","commonSituations":"Read-only credentials used for cleanup jobs; bucket policy changed to deny deletes; object under a retention/legal-hold-like policy; transient network outage during batch deletion.","solutions":["Check the wrapped error's code/status: 403 means grant DeleteObject (or s3:* on the prefix) to the configured AK/SK.","Confirm bucket name in config matches the bucket encoded in stored ks3:// paths.","For batch deletes, add retry/backoff around DeleteFile for 5xx/timeouts; SDK already retries 3 times.","If the object is protected by a retention policy, remove the hold or delete via the console with admin rights.","Treat 'delete failed but object actually gone' idempotently: verify with HeadObject before recreating records."],"exampleFix":"// before\nerr := svc.DeleteFile(ctx, path) // fails with 403\n// after\n// attach a policy allowing DeleteObject on the prefix, then retry:\n// {\"Effect\":\"Allow\",\"Action\":\"s3:DeleteObject\",\"Resource\":\"arn:aws:s3:::bucket/prefix/*\"}\nerr = svc.DeleteFile(ctx, path)","handlingStrategy":"retry","validationCode":"// ensure object exists before delete if error must be meaningful\n// (S3/KS3 DeleteObject is idempotent for missing keys)","typeGuard":null,"tryCatchPattern":"err := svc.DeleteFile(ctx, path)\nif err != nil {\n\tif strings.Contains(err.Error(), \"403\") {\n\t\t// fix credentials/policy, do not retry\n\t} else {\n\t\t// transient: retry with exponential backoff, max 3 attempts\n\t}\n}","preventionTips":["Grant DeleteObject (or prefix-scoped s3:*) to the runtime AK/SK","Make deletion jobs idempotent — treat already-deleted as success","Run CheckConnectivity before batch delete jobs"],"tags":["ks3","object-storage","permissions","network","go"],"backgroundTag":"s3-delete-object-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}