ppy/osu · error · InvalidOperationException

Beatmap file {b.File!.Filename} could not be opened!

Error message

Beatmap file {b.File!.Filename} could not be opened!

What it means

Thrown by LegacyBeatmapExporter.ExportAsync when GetFileContents(b.BeatmapSet, b.File) returns null while exporting a single beatmap to .osz. GetFileContents resolves the file's on-disk storage path via UserFileStorage.GetStream; a null result means the backing file blob is missing from the realm file store even though the BeatmapInfo references it. The surrounding try/catch cancels the progress notification, deletes the partially-created export file, and rethrows.

Source

Thrown at osu.Game/Database/LegacyBeatmapExporter.cs:242

            string filename = NamingUtils.GetNextBestFilename(existingExports, $"{itemFilename}{osu_extension}");

            ProgressNotification notification = new ProgressNotification
            {
                State = ProgressNotificationState.Active,
                Text = NotificationsStrings.FileExportOngoing(itemFilename),
            };

            PostNotification?.Invoke(notification);

            try
            {
                beatmap.PerformRead(b =>
                {
                    using var exportStream = ExportStorage.CreateFileSafely(filename);
                    using var inputFile = GetFileContents(b.BeatmapSet!, b.File!);

                    if (inputFile == null)
                        throw new InvalidOperationException($"Beatmap file {b.File!.Filename} could not be opened!");

                    inputFile.CopyTo(exportStream);
                });
            }
            catch
            {
                notification.State = ProgressNotificationState.Cancelled;

                // cleanup if export is failed or canceled.
                ExportStorage.Delete(filename);
                throw;
            }

            notification.CompletionText = NotificationsStrings.FileExportFinished(itemFilename);
            notification.CompletionClickAction = () => ExportStorage.PresentFileExternally(filename);
            notification.State = ProgressNotificationState.Completed;
        });
    }

View on GitHub (pinned to d9c73e12ad)

Solutions

  1. Verify the beatmap's file actually exists on disk before exporting: check b.BeatmapSet.Files for the named file and RealmFileStore.Store.GetStream(file.File.GetStoragePath()) returns non-null.
  2. If the file is genuinely missing, repair or re-import the beatmap set (re-download or re-import the .osz) so the backing blob is present, then retry the export.
  3. If recurring across many beatmaps, run a storage integrity check / re-link missing files; investigate whether a prior MigratableStorage.Migrate or file cleanup deleted blobs without updating realm.

Example fix

// before
beatmap.PerformRead(b =>
{
    using var inputFile = GetFileContents(b.BeatmapSet!, b.File!);
    if (inputFile == null)
        throw new InvalidOperationException($"Beatmap file {b.File!.Filename} could not be opened!");
    // ...
});

// after (guard at call site, degrade gracefully)
if (beatmap.PerformRead(b => RealmFileStore.Store.GetStream(b.File!.File.GetStoragePath())) == null)
{
    notification.State = ProgressNotificationState.Cancelled;
    return;
}
Defensive patterns

Strategy: validation

Validate before calling

// Verify the beatmap's file blob exists on disk before exporting.
bool canExport = beatmap.PerformRead(b =>
{
    if (b.File == null || b.BeatmapSet == null) return false;
    string path = b.File.File.GetStoragePath();
    return !string.IsNullOrEmpty(path) && realmFileStore.Store.GetStream(path) != null;
});
if (!canExport) { /* show 'file missing' notification */ }

Type guard

static bool HasBackingFile(BeatmapSetInfo set, INamedFileUsage file, RealmFileStore store)
    => file?.File != null && store.Store.GetStream(file.File.GetStoragePath()) != null;

Try / catch

try { await exporter.ExportAsync(beatmap); }
catch (InvalidOperationException ex) when (ex.Message.Contains("could not be opened"))
{
    Notifications.Post(new SimpleNotification { Text = "The beatmap file is missing from disk. Try re-importing it." });
}

Prevention

When it happens

Trigger: Calling ExportAsync(beatmap) on a Live<BeatmapInfo> whose b.File / b.BeatmapSet points at a RealmNamedFileUsage whose underlying RealmFile no longer exists on disk (store path missing, file deleted out-of-band, or corrupted realm). The null check at line 241 fires before CopyTo would NRE.

Common situations: User opens a beatmap info context menu and picks 'Export'; the beatmap set had files pruned or migrated incompletely (e.g. after a failed storage migration, manual deletion of files/ directory, or a realm restore from a backup whose blobs weren't copied). Also seen when a beatmap's File navigation property is stale after the file was replaced/deleted in another transaction.

Related errors


AI-assisted analysis of ppy/osu@d9c73e12ad (2026-08-13). Data as JSON: /api/errors/c70dcb5eb6abf890. Report an issue: GitHub.