files-community/Files · error · FileNotFoundException

File was not found from path.

Error message

File was not found from path.

What it means

Thrown by FtpStorageService.GetFileAsync as FileNotFoundException. It connects, resolves the FTP path, and calls GetObjectInfo; if the result is null (path does not exist) or its Type is not FtpObjectType.File (e.g. the id actually names a directory), it cannot be returned as an IFile.

Source

Thrown at src/Files.App.Storage/Ftp/FtpStorageService.cs:35

			var ftpPath = FtpHelpers.GetFtpPath(id);
			var item = await ftpClient.GetObjectInfo(ftpPath, token: cancellationToken);
			if (item is null || item.Type != FtpObjectType.Directory)
				throw new DirectoryNotFoundException("Directory was not found from path.");

			return new FtpStorageFolder(ftpPath, item.Name, null);
		}

		/// <inheritdoc/>
		public async Task<IFile> GetFileAsync(string id, CancellationToken cancellationToken = default)
		{
			using var ftpClient = FtpHelpers.GetFtpClient(id);
			await ftpClient.EnsureConnectedAsync(cancellationToken);

			var ftpPath = FtpHelpers.GetFtpPath(id);
			var item = await ftpClient.GetObjectInfo(ftpPath, token: cancellationToken);
			if (item is null || item.Type != FtpObjectType.File)
				throw new FileNotFoundException("File was not found from path.");

			return new FtpStorageFile(ftpPath, item.Name, null);
		}
	}
}

View on GitHub (pinned to 68c68a58d4)

Solutions

  1. Confirm the path exists and is a file before resolving; fall back to GetFolderAsync if the id names a directory.
  2. Catch FileNotFoundException and show a clear 'file not available' message rather than a raw stack.
  3. Verify the server supports MLST/STAT (check FluentFTP server capabilities) or fall back to a LIST-based lookup.
  4. Re-resolve from a known parent folder by name to recover from renames.

Example fix

// before
var file = await service.GetFileAsync(id, ct);

// after
try { return await service.GetFileAsync(id, ct); }
catch (FileNotFoundException) {
    try { return await service.GetFolderAsync(id, ct); }
    catch { throw; }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the id is a file before resolving.
var ftpPath = FtpHelpers.GetFtpPath(id);
var info = await ftpClient.GetObjectInfo(ftpPath, token: ct);
if (info is null || info.Type != FtpObjectType.File)
    throw new FileNotFoundException(id);

Type guard

static async Task<bool> IsFtpFileAsync(AsyncFtpClient client, string path, CancellationToken ct)
{ var i = await client.GetObjectInfo(path, token: ct); return i is { Type: FtpObjectType.File }; }

Try / catch

try { return await service.GetFileAsync(id, ct); }
catch (FileNotFoundException) { try { return await service.GetFolderAsync(id, ct); } catch { throw; } }

Prevention

When it happens

Trigger: GetFileAsync(id) where id resolves to a missing path or to a directory. Also when GetObjectInfo returns null due to the server not supporting STAT/MLST or denying access.

Common situations: Deep link / shell activation with a stale or moved file path; opening a path that is actually a folder; permission changes that hide the file from listings; FTP servers without MLST support returning null from GetObjectInfo for valid files.

Related errors


AI-assisted analysis of files-community/Files@68c68a58d4 (2026-08-13). Data as JSON: /api/errors/1fdb93c5e475e82b. Report an issue: GitHub.