apache/hadoop · error · FileNotFoundException

Item not found: %s

Error message

Item not found: %s

What it means

The client read channel's static validate(itemInfo) throws FileNotFoundException("Item not found: <resourceId>") when opening a channel for an object whose GoogleCloudStorageItemInfo.exists() is false. It first asserts the id is a storage object (not a bucket or root). This runs at open time, before any bytes are requested.

Source

Thrown at hadoop-cloud-storage-project/hadoop-gcp/src/main/java/org/apache/hadoop/fs/gs/GoogleCloudStorageClientReadChannel.java:569

        blobReadOptions.add(BlobSourceOption.generationMatch(blobId.getGeneration()));
      }

      // TODO: Add support for encryptionKey
      return blobReadOptions.toArray(new BlobSourceOption[blobReadOptions.size()]);
    }

    private boolean isFooterRead() {
      return objectSize - currentPosition <= config.getMinRangeRequestSize();
    }
  }

  private static void validate(GoogleCloudStorageItemInfo itemInfo) throws IOException {
    checkNotNull(itemInfo, "itemInfo cannot be null");
    StorageResourceId resourceId = itemInfo.getResourceId();
    checkArgument(
        resourceId.isStorageObject(), "Can not open a non-file object for read: %s", resourceId);
    if (!itemInfo.exists()) {
      throw new FileNotFoundException(String.format("Item not found: %s", resourceId));
    }
  }

  private IOException convertError(Exception error) {
    String msg = String.format("Error reading '%s'", resourceId);
    switch (ErrorTypeExtractor.getErrorType(error)) {
    case NOT_FOUND:
      return createFileNotFoundException(
          resourceId.getBucketName(), resourceId.getObjectName(), new IOException(msg, error));
    case OUT_OF_RANGE:
      return (IOException) new EOFException(msg).initCause(error);
    default:
      return new IOException(msg, error);
    }
  }

  /** Validates that the given position is valid for this channel. */
  private void validatePosition(long position) throws IOException {

View on GitHub (pinned to 2add963021)

Solutions

  1. Re-stat the path with getItemInfo immediately before opening and handle absence in application logic.
  2. For rename/commit races, use an idempotent output committer and serialize producer/cleanup of the same paths.
  3. If pinning generations intentionally, catch FileNotFoundException and re-fetch item info for the live generation.
  4. Fix path construction (URI encoding, leading slashes, case).

Example fix

// before
try (SeekableByteChannel ch = gcs.open(itemInfo)) { ... } // FileNotFoundException

// after
GoogleCloudStorageItemInfo fresh = gcs.getItemInfo(itemInfo.getResourceId());
if (!fresh.exists()) {
  return; // or throw domain-specific 'input vanished' error
}
try (SeekableByteChannel ch = gcs.open(fresh)) { ... }
Defensive patterns

Strategy: validation

Validate before calling

GoogleCloudStorageItemInfo fresh = gcs.getItemInfo(resourceId);
if (!fresh.exists()) {
  throw new MissingInputException(resourceId); // domain-specific, actionable
}
try (SeekableByteChannel ch = gcs.open(fresh)) { /* read */ }

Try / catch

catch (FileNotFoundException e) {
  // input vanished (deleted/moved concurrently): re-stat to distinguish typo vs race
  if (!gcs.getItemInfo(resourceId).exists()) throw e;
  /* else stale info: retry open with fresh item info */
}

Prevention

When it happens

Trigger: gcs.open(itemInfo) / GHFS open() on a path that was deleted, never existed, or whose pinned generation no longer exists; opening from itemInfo taken from a stale listing or cache after the object was removed.

Common situations: Races between concurrent jobs (output committer cleanup deleting temp files while another task reads them); stale directory listings; typo'd or wrongly-encoded paths; objects deleted and recreated while a reader pinned the old generation.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/5e1d1f6af9dc2d1a. Report an issue: GitHub.