apache/iceberg · error · NotFoundException

Failed to open file

Error message

Failed to open file: %s

What it means

ContentCache.newStream wraps a FileNotFoundException from the cached-stream path into a NotFoundException, meaning the file could not be opened even though a cached read was attempted. Any other IOException falls back to the uncached delegate stream instead of failing.

Solutions

  1. Verify the file location exists in storage (ls/stat the object) before or at read time.
  2. Re-plan the scan to get a fresh snapshot; the file may have been expired.
  3. Check for concurrent table maintenance (expireSnapshots/rewriteDataFiles) racing readers.
  4. Fix path/region configuration if the location is systematically wrong.

Example fix

// before
SeekableInputStream in = cacheFile.newStream(); // NotFoundException
// after
if (!io.newInputFile(location).exists()) {
  LOG.warn("File {} missing, re-planning scan", location);
  return replanAndRead(location);
}
SeekableInputStream in = cacheFile.newStream();
Defensive patterns

Strategy: fallback

Validate before calling

boolean exists = io.newInputFile(location).exists();
if (!exists) { replanOrSkip(location); }

Try / catch

try {
  return cachedFile.newStream();
} catch (NotFoundException e) {
  LOG.warn("File {} not found, falling back to replan", location);
  return replannedFile.newStream();
}

Prevention

When it happens

Trigger: Calling newStream() on a caching InputFile whose underlying file is missing (deleted between planning and read, wrong path, or not yet visible), and cachedStream() propagates FileNotFoundException.

Common situations: Reading a data file deleted by compaction/expiry while a long-running scan still references it; mistyped or stale file location; eventual-consistency lag after write in S3-compatible stores.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/io/ContentCache.java:214

    }

    /**
     * Opens a new {@link SeekableInputStream} for the underlying data file, either from cache or
     * from the inner FileIO.
     *
     * <p>If data file is not cached yet, and it can fit in the cache, the file content will be
     * cached first before returning a {@link ByteBufferInputStream}. Otherwise, return a new
     * SeekableInputStream from the inner FIleIO.
     *
     * @return a {@link ByteBufferInputStream} if file exist in the cache or can fit in the cache.
     *     Otherwise, return a new SeekableInputStream from the inner FIleIO.
     */
    @Override
    public SeekableInputStream newStream() {
      try {
        return cachedStream();
      } catch (FileNotFoundException e) {
        throw new NotFoundException(e, "Failed to open file: %s", input.location());
      } catch (IOException e) {
        return input.newStream();
      }
    }

    @Override
    public String location() {
      return input.location();
    }

    @Override
    public boolean exists() {
      FileContent buf = contentCache.cache.getIfPresent(input.location());
      return buf != null || input.exists();
    }

    private SeekableInputStream cachedStream() throws IOException {
      try {

View on GitHub (pinned to 86d9c8fc54)