apache/iceberg · warning

Failed to add delete tags

Error message

Failed to add delete tags: {} to {}

What it means

A warning from S3FileIO.deleteFile: the configured delete tags could not be applied to the object via tagFileToDelete (an S3Exception was raised), but the delete itself is NOT aborted — after logging, the code proceeds with the actual deletion unless deletion is disabled. The tags (often used for lifecycle-based soft delete or recovery, e.g. with the S3 Tables recovery feature) are simply missing on the object.

Solutions

  1. Grant the principal s3:PutObjectTagging (and s3:GetObjectTagging) on the bucket/objects in the IAM policy
  2. If you don't need delete tags, unset s3.delete.tags so the tagging step is skipped entirely
  3. Verify object ownership settings allow tagging from the writing account
  4. Note the file is still deleted after the warning; if tags were your safety net for recovery, consider enabling delete=false plus a lifecycle policy instead

Example fix

// before
{
  "Effect": "Allow",
  "Action": ["s3:DeleteObject"],
  "Resource": "arn:aws:s3:::my-bucket/*"
}
// after
{
  "Effect": "Allow",
  "Action": ["s3:DeleteObject", "s3:PutObjectTagging", "s3:GetObjectTagging"],
  "Resource": "arn:aws:s3:::my-bucket/*"
}
Defensive patterns

Strategy: validation

Validate before calling

// verify tagging permission before deletes
try {
  s3.getObjectTagging(b -> b.bucket(bucket).key(key));
} catch (S3Exception e) {
  LOG.warn("Tagging not permitted on {}", key); // PutObjectTagging will fail too
}

Prevention

When it happens

Trigger: s3.delete.tags is configured and non-empty, but Object PutTagging fails — typically missing s3:PutObjectTagging permission, object already deleted by a concurrent writer, object versioning issues, or KMS/ownership restrictions.

Common situations: IAM policies granting s3:DeleteObject but not s3:PutObjectTagging; buckets with Object Ownership set to bucket-owner-enforced and cross-account tagging restrictions; expireSnapshot/delete operations where a concurrent compaction already removed the file.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/f442ef19d234a8b3. Report an issue: GitHub.

Appendix: source

Thrown at aws/src/main/java/org/apache/iceberg/aws/s3/S3FileIO.java:173

  @Override
  public InputFile newInputFile(String path, long length) {
    return S3InputFile.fromLocation(path, length, clientForStoragePath(path), metrics);
  }

  @Override
  public OutputFile newOutputFile(String path) {
    return S3OutputFile.fromLocation(path, clientForStoragePath(path), metrics);
  }

  @Override
  public void deleteFile(String path) {
    PrefixedS3Client client = clientForStoragePath(path);
    S3FileIOProperties s3FileIOProperties = client.s3FileIOProperties();
    if (s3FileIOProperties.deleteTags() != null && !s3FileIOProperties.deleteTags().isEmpty()) {
      try {
        tagFileToDelete(client, path, s3FileIOProperties.deleteTags());
      } catch (S3Exception e) {
        LOG.warn("Failed to add delete tags: {} to {}", s3FileIOProperties.deleteTags(), path, e);
      }
    }

    if (!s3FileIOProperties.isDeleteEnabled()) {
      return;
    }

    S3URI location = new S3URI(path, s3FileIOProperties.bucketToAccessPointMapping());
    DeleteObjectRequest deleteRequest =
        DeleteObjectRequest.builder().bucket(location.bucket()).key(location.key()).build();

    client.s3().deleteObject(deleteRequest);
  }

  @Override
  public Map<String, String> properties() {
    return properties.immutableMap();
  }

View on GitHub (pinned to 86d9c8fc54)