apache/druid · error · RuntimeException (RE)

Error fetching last modified timestamp from URI [%s]

Error message

Error fetching last modified timestamp from URI [%s]

What it means

Same code path as the recoverable variant, but thrown when the SdkException from the HeadObject call is classified as non-recoverable. It is wrapped in a RuntimeException (RE) because retrying is not expected to help.

Source

Thrown at extensions-core/s3-extensions/src/main/java/org/apache/druid/storage/s3/S3DataSegmentPuller.java:313

   * @return The time in ms of the last modification of the URI in String format
   * @throws IOException
   */
  @Override
  public String getVersion(URI uri) throws IOException
  {
    try {
      final CloudObjectLocation coords = new CloudObjectLocation(S3Utils.checkURI(uri));
      final HeadObjectResponse objectMetadata =
          S3Utils.getSingleObjectMetadata(s3Client, coords.getBucket(), coords.getPath());
      Instant lastModified = objectMetadata.lastModified();
      return StringUtils.format("%d", lastModified != null ? lastModified.toEpochMilli() : 0L);
    }
    catch (SdkException e) {
      if (AWSClientUtil.isClientExceptionRecoverable(e)) {
        // The recoverable logic is always true for IOException, so we want to only pass IOException if it is recoverable
        throw new IOE(e, "Could not fetch last modified timestamp from URI [%s]", uri);
      } else {
        throw new RE(e, "Error fetching last modified timestamp from URI [%s]", uri);
      }
    }
  }

}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Verify the segment URI (bucket/key) exists in S3.
  2. Check IAM credentials and policy for s3:GetObject/s3:ListBucket permissions.
  3. Confirm the configured region/endpoint matches the bucket's region.
  4. Fix the underlying configuration; do not retry, the error is permanent.

Example fix

// before
String v = puller.getVersion(maybeMissingUri);
// after
if (S3Utils.isObjectInBucket(s3Client, bucket, key)) {
  String v = puller.getVersion(maybeMissingUri);
}
Defensive patterns

Strategy: try-catch

Validate before calling

boolean exists = S3Utils.isObjectInBucket(s3Client, bucket, key);

Try / catch

try { v = puller.getVersion(uri); } catch (RuntimeException e) { log.error("Permanent failure fetching %s", uri, e); throw e; }

Prevention

When it happens

Trigger: Calling version()/getVersion() when S3 returns a permanent error: 404 NoSuchKey/403 AccessDenied, invalid credentials, malformed request, or other non-retryable SDK failures.

Common situations: Segment descriptor points to a deleted or never-uploaded object; wrong bucket or region configuration; IAM policy missing s3:GetObject on the segment prefix.

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/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/f6096f7d2a505101. Report an issue: GitHub.