bumptech/glide · error · FileNotFoundException

FileDescriptor is null for: {uri}

Error message

FileDescriptor is null for: {uri}

What it means

FileDescriptorLocalUriFetcher loads a local content Uri via openAssetFileDescriptor and then extracts the ParcelFileDescriptor. If the ContentResolver returns null for openAssetFileDescriptor, there is no file descriptor to read, and Glide throws a FileNotFoundException naming the Uri. This is the ParcelFileDescriptor-based counterpart of the AssetFileDescriptor fetcher.

Source

Thrown at library/src/main/java/com/bumptech/glide/load/data/FileDescriptorLocalUriFetcher.java:31

  public FileDescriptorLocalUriFetcher(ContentResolver contentResolver, Uri uri) {
    super(contentResolver, uri);
  }

  /**
   * useMediaStoreApisIfAvailable is part of an experiment and the constructor can be removed in a
   * future version.
   */
  public FileDescriptorLocalUriFetcher(
      ContentResolver contentResolver, Uri uri, boolean useMediaStoreApisIfAvailable) {
    super(contentResolver, uri, useMediaStoreApisIfAvailable);
  }

  @Override
  protected ParcelFileDescriptor loadResource(Uri uri, ContentResolver contentResolver)
      throws FileNotFoundException {
    AssetFileDescriptor assetFileDescriptor = openAssetFileDescriptor(uri);
    if (assetFileDescriptor == null) {
      throw new FileNotFoundException("FileDescriptor is null for: " + uri);
    }
    return assetFileDescriptor.getParcelFileDescriptor();
  }

  @Override
  protected void close(ParcelFileDescriptor data) throws IOException {
    data.close();
  }

  @NonNull
  @Override
  public Class<ParcelFileDescriptor> getDataClass() {
    return ParcelFileDescriptor.class;
  }
}

View on GitHub (pinned to eb14a895d8)

Solutions

  1. Verify content exists at the Uri using ContentResolver#query before loading
  2. Add an .error() placeholder and handle the failure gracefully in RequestListener
  3. Ensure persisted URI permissions (takePersistableUriPermission) are still valid if using a persisted Uri
  4. Register a custom data fetcher if the content provider only supports openInputStream

Example fix

// before
Glide.with(context).load(videoUri).into(imageView);
// after
Glide.with(context)
  .load(videoUri)
  .error(R.drawable.video_placeholder)
  .into(imageView);
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify content exists before loading
private boolean contentExists(ContentResolver cr, Uri uri) {
  try (Cursor c = cr.query(uri, null, null, null, null)) {
    return c != null && c.getCount() > 0;
  } catch (Exception e) {
    return false;
  }
}
if (contentExists(getContentResolver(), uri)) {
  Glide.with(context).load(uri).into(imageView);
}

Try / catch

Glide.with(context)
  .load(uri)
  .error(R.drawable.placeholder)
  .listener(new RequestListener<Drawable>() {
    @Override public boolean onLoadFailed(GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
      for (Throwable root : e.getRootCauses()) {
        if (root instanceof FileNotFoundException) {
          Log.w(TAG, "FileDescriptor unavailable for " + model);
        }
      }
      return false;
    }
    @Override public boolean onResourceReady(Drawable r, Object m, Target<Drawable> t, DataSource d, boolean i) { return false; }
  })
  .into(imageView);

Prevention

When it happens

Trigger: Loading a video thumbnail or local file Uri via the FileDescriptor path when the content has been deleted. Content provider does not support openAssetFileDescriptor for the given Uri. Permission to access the content was revoked.

Common situations: Loading video frames from a MediaStore Uri after the media file was moved or deleted. Accessing content from another app's FileProvider without proper grants. Background service loading media after a user cleared app data.

Related errors


AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14). Data as JSON: /api/errors/8766582db196e552. Report an issue: GitHub.