{"record":{"id":"ea6eb30b28f3dfb2","repo":"kubernetes/kops","slug":"error-deleting-s-v","errorCode":null,"errorMessage":"error deleting %s: %v","messagePattern":"error deleting (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/pkg/vfs/s3fs.go","lineNumber":124,"sourceCode":"}\n\nfunc (p *S3Path) Remove(ctx context.Context) error {\n\tclient, err := p.client(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tklog.V(8).Infof(\"removing file %s\", p)\n\n\trequest := &s3.DeleteObjectInput{}\n\trequest.Bucket = aws.String(p.bucket)\n\trequest.Key = aws.String(p.key)\n\n\t_, err = client.DeleteObject(ctx, request)\n\tif err != nil {\n\t\t// TODO: Check for not-exists, return os.NotExist\n\n\t\treturn fmt.Errorf(\"error deleting %s: %v\", p, err)\n\t}\n\n\treturn nil\n}\n\nfunc (p *S3Path) RemoveAll(ctx context.Context) error {\n\tclient, err := p.client(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttree, err := p.ReadTree(ctx)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tobjects := make([]types.ObjectIdentifier, len(tree))\n\tfor i := range tree {","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/util/pkg/vfs/s3fs.go#L106-L142","documentation":"S3Path.Remove deletes a single object from S3 via DeleteObject. When the S3 API call fails for any reason (permissions, networking, bucket state), the error is wrapped as \"error deleting <path>: <underlying error>\". The TODO in the source notes that a not-exists response is not yet translated to os.ErrNotExist, so even a missing object surfaces through this wrapper.","triggerScenarios":"Calling vfs context Remove() on an S3Path when: the IAM credentials lack s3:DeleteObject on the key; the AWS request fails (throttling, network, expired credentials); the bucket is in a region/account the client cannot reach; the object key is invalid or the bucket does not exist.","commonSituations":"Running `kops delete cluster` or state-store cleanup with a read-only state store policy; corporate proxy or VPC endpoint blocking S3; expired STS session tokens during long operations; typos in KOPS_STATE_STORE bucket name.","solutions":["Read the wrapped %v error to identify the AWS failure code (AccessDenied, NoSuchBucket, etc.)","Verify the credentials/role used have s3:DeleteObject permission on the state-store bucket/prefix","Confirm KOPS_STATE_STORE points at the correct bucket and region (AWS_REGION / bucket region match)","Re-run after fixing transient network/throttling issues; consider AWS SDK retries"],"exampleFix":"// before (library TODO): not-exists is not mapped\nreturn fmt.Errorf(\"error deleting %s: %v\", p, err)\n// after (caller-side handling)\nif err := ctx.Remove(p); err != nil {\n\tif AWSErrorCode(err) == \"NoSuchKey\" || strings.Contains(err.Error(), \"NotFound\") {\n\t\treturn nil // already gone\n\t}\n\treturn err\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check delete permission minimally\n_, err := s3Client.DeleteObjectTagging(ctx, &s3.DeleteObjectTaggingInput{Bucket: bucket, Key: aws.String(key)})\n// treat AccessDenied as \"will fail\" before attempting Remove","typeGuard":null,"tryCatchPattern":"err := vfs.Context.Remove(p)\nif err != nil {\n\tif AWSErrorCode(err) == \"AccessDenied\" {\n\t\treturn fmt.Errorf(\"no s3:DeleteObject on %s: %w\", p, err)\n\t}\n\tif errors.Is(err, context.DeadlineExceeded) { /* retry */ }\n\treturn err\n}","preventionTips":["Grant s3:DeleteObject (and DeleteObjects) on the state-store prefix in the IAM role","Confirm bucket name and region before destructive operations","Handle os.ErrNotExist semantics yourself — the library does not map not-found for Remove"],"tags":["aws","s3","delete","permissions"],"backgroundTag":"s3-delete-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}