immich-app/immich · error · Exception

No file found for the video

Error message

No file found for the video

What it means

Thrown during video player source initialization in VideoViewerWidget when a localFilePath was supplied but the file does not exist on disk. VideoSource.init with VideoSourceType.file would fail otherwise, so the widget validates existence first with File.exists(). It means the player was handed a path whose backing file was removed or never downloaded.

Solutions

  1. Check File.existsSync(localFilePath) before initializing the player and fall back to streaming the remote asset instead.
  2. Trigger a re-download of the asset if the local copy is missing.
  3. Purge stale localFilePath entries from local storage/DB when files are evicted.
  4. Handle the exception in the player UI by showing a 'video unavailable' state and retry logic.

Example fix

// before
if (!await file.exists()) {
  throw Exception('No file found for the video');
}
// after
if (!await file.exists()) {
  // fall back to remote streaming source instead of throwing
  return await VideoSource.init(url: widget.asset.remoteUrl, type: VideoSourceType.network);
}
Defensive patterns

Strategy: fallback

Validate before calling

final file = File(localFilePath);
if (!await file.exists()) {
  // trigger re-download or use remote streaming source
  return;
}

Type guard

Future<bool> hasLocalFile(String? path) async =>
    path != null && await File(path).exists();

Try / catch

try {
  final source = await initVideoSource();
  // attach player
} catch (e) {
  setState(() => playbackError = 'Video file missing; streaming remotely...');
  await playFromRemote();
}

Prevention

When it happens

Trigger: widget.localFilePath is non-null but the file at that path cannot be found — e.g. the local cache was cleared, the asset was deleted, or the path was recorded before the download completed.

Common situations: OS/storage cleaner evicted cached video files; app data cleared between sessions; a stale DB record pointing to a removed temp file; path stored before a cancelled download.

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 immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/29240cee19bd9322. Report an issue: GitHub.

Appendix: source

Thrown at mobile/lib/presentation/widgets/asset_viewer/video_viewer.widget.dart:121

  }

  Future<VideoSource?> _createSource() async {
    if (!mounted) {
      return null;
    }

    final videoAsset = await ref.read(assetServiceProvider).getAsset(widget.asset) ?? widget.asset;
    if (!mounted) {
      return null;
    }

    try {
      final localFilePath = widget.localFilePath;
      if (localFilePath != null) {
        final file = File(localFilePath);
        // ignore: avoid_slow_async_io
        if (!await file.exists()) {
          throw Exception('No file found for the video');
        }

        return await VideoSource.init(
          path: CurrentPlatform.isAndroid ? file.uri.toString() : file.path,
          type: VideoSourceType.file,
        );
      }

      // Attempt to retrieve LocalAsset, falling back to remote if it cannot be found
      final localAsset = await _localPlaybackAsset(videoAsset);

      if (localAsset != null) {
        final file = localAsset.isMotionPhoto
            ? await StorageRepository().getMotionFileForAsset(localAsset)
            : await StorageRepository().getFileForAsset(localAsset.id);

        if (!mounted) {
          return null;

View on GitHub (pinned to e55ac299a4)