{"record":{"id":"c70dcb5eb6abf890","repo":"ppy/osu","slug":"beatmap-file-b-file-filename-could-not-be-opene","errorCode":null,"errorMessage":"Beatmap file {b.File!.Filename} could not be opened!","messagePattern":"Beatmap file (.+?) could not be opened!","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"osu.Game/Database/LegacyBeatmapExporter.cs","lineNumber":242,"sourceCode":"            string filename = NamingUtils.GetNextBestFilename(existingExports, $\"{itemFilename}{osu_extension}\");\r\n\r\n            ProgressNotification notification = new ProgressNotification\r\n            {\r\n                State = ProgressNotificationState.Active,\r\n                Text = NotificationsStrings.FileExportOngoing(itemFilename),\r\n            };\r\n\r\n            PostNotification?.Invoke(notification);\r\n\r\n            try\r\n            {\r\n                beatmap.PerformRead(b =>\r\n                {\r\n                    using var exportStream = ExportStorage.CreateFileSafely(filename);\r\n                    using var inputFile = GetFileContents(b.BeatmapSet!, b.File!);\r\n\r\n                    if (inputFile == null)\r\n                        throw new InvalidOperationException($\"Beatmap file {b.File!.Filename} could not be opened!\");\r\n\r\n                    inputFile.CopyTo(exportStream);\r\n                });\r\n            }\r\n            catch\r\n            {\r\n                notification.State = ProgressNotificationState.Cancelled;\r\n\r\n                // cleanup if export is failed or canceled.\r\n                ExportStorage.Delete(filename);\r\n                throw;\r\n            }\r\n\r\n            notification.CompletionText = NotificationsStrings.FileExportFinished(itemFilename);\r\n            notification.CompletionClickAction = () => ExportStorage.PresentFileExternally(filename);\r\n            notification.State = ProgressNotificationState.Completed;\r\n        });\r\n    }\r","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/ppy/osu/blob/d9c73e12adff2feaae4a3e158d36fe5883faf6ca/osu.Game/Database/LegacyBeatmapExporter.cs#L224-L260","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","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.","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."],"exampleFix":"// before\nbeatmap.PerformRead(b =>\n{\n    using var inputFile = GetFileContents(b.BeatmapSet!, b.File!);\n    if (inputFile == null)\n        throw new InvalidOperationException($\"Beatmap file {b.File!.Filename} could not be opened!\");\n    // ...\n});\n\n// after (guard at call site, degrade gracefully)\nif (beatmap.PerformRead(b => RealmFileStore.Store.GetStream(b.File!.File.GetStoragePath())) == null)\n{\n    notification.State = ProgressNotificationState.Cancelled;\n    return;\n}","handlingStrategy":"validation","validationCode":"// Verify the beatmap's file blob exists on disk before exporting.\nbool canExport = beatmap.PerformRead(b =>\n{\n    if (b.File == null || b.BeatmapSet == null) return false;\n    string path = b.File.File.GetStoragePath();\n    return !string.IsNullOrEmpty(path) && realmFileStore.Store.GetStream(path) != null;\n});\nif (!canExport) { /* show 'file missing' notification */ }","typeGuard":"static bool HasBackingFile(BeatmapSetInfo set, INamedFileUsage file, RealmFileStore store)\n    => file?.File != null && store.Store.GetStream(file.File.GetStoragePath()) != null;","tryCatchPattern":"try { await exporter.ExportAsync(beatmap); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"could not be opened\"))\n{\n    Notifications.Post(new SimpleNotification { Text = \"The beatmap file is missing from disk. Try re-importing it.\" });\n}","preventionTips":["Never delete or move files under the realm file store except through ModelManager/realmFileStore APIs.","After a storage migration, run an integrity pass that verifies every RealmNamedFileUsage resolves to a non-null stream.","When re-importing or replacing beatmap sets, ensure the old File references are updated atomically."],"tags":["filesystem","export","realm","beatmap","data-integrity"],"backgroundTag":null,"analyzedSha":"d9c73e12adff2feaae4a3e158d36fe5883faf6ca","analyzedAt":"2026-08-13T14:12:54.015Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}