apache/iceberg · warning

Failed to recover object

Error message

Failed to recover object {}

What it means

S3FileIO.recoverObject() restores an object version (e.g. from a versioning-enabled bucket) by copying a prior version back to the key. If the AWS SDK copy raises SdkException, it logs this warning with the version key and returns false, signaling recovery failed for that object.

Solutions

  1. Enable bucket versioning before relying on recovery features
  2. Verify IAM grants GetObjectVersion and PutObject on the bucket
  3. Check the attached exception: NoSuchVersion means the version was expired by lifecycle policy
  4. Confirm the version id exists via list-object-versions before recovering
Defensive patterns

Strategy: validation

Validate before calling

// confirm versioning is on and the version exists before recovery
BucketVersioningConfiguration v = s3Client.getBucketVersioning(b -> b.bucket(bucket));
if (!"Enabled".equals(v.getStatus())) throw new IllegalStateException("versioning disabled");

Try / catch

boolean ok = io.recoverFile(path); if (!ok) { /* object not recovered; inspect S3FileIO logs for 'Failed to recover object' */ }

Prevention

When it happens

Trigger: recoverFile() called on a bucket without versioning enabled (no prior version to copy), or the caller lacks s3:GetObjectVersion/s3:PutObject permission, or the source version no longer exists (expired lifecycle).

Common situations: Attempted rollback of accidental deletes on buckets where versioning/safeguard feature was never enabled; lifecycle rules purging old versions; cross-account permission gaps.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

      return true;
    }

    LOG.info("Attempting to recover object {}", version.key());
    try {
      // Perform a copy instead of deleting the delete marker
      // so that recovery does not rely on delete permissions
      client
          .s3()
          .copyObject(
              builder ->
                  builder
                      .sourceBucket(bucket)
                      .sourceKey(version.key())
                      .sourceVersionId(version.versionId())
                      .destinationBucket(bucket)
                      .destinationKey(version.key()));
    } catch (SdkException e) {
      LOG.warn("Failed to recover object {}", version.key(), e);
      return false;
    }

    return true;
  }

  @Override
  public void setCredentials(List<StorageCredential> credentials) {
    Preconditions.checkArgument(credentials != null, "Invalid storage credentials: null");
    // stop any refresh that might be scheduled
    if (refreshFuture != null) {
      refreshFuture.cancel(true);
    }

    // copy credentials into a modifiable collection for Kryo serde
    this.storageCredentials = Lists.newArrayList(credentials);

    // if the clients are already initialized, we need to close and allow them to be recreated

View on GitHub (pinned to 86d9c8fc54)