{"record":{"id":"9899fad930919e61","repo":"dotnet/machinelearning","slug":"model-file-filepath-still-got-locked-after-5-se","errorCode":null,"errorMessage":"Model file {_filePath} still got locked after 5 seconds, fail to reload.","messagePattern":"Model file (.+?) still got locked after 5 seconds, fail to reload\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.Extensions.ML/ModelLoaders/FileModelLoader.cs","lineNumber":136,"sourceCode":"                catch (IOException)\n                {\n                    if (fs != null)\n                    {\n                        fs.Dispose();\n                    }\n                    Thread.Sleep(50);\n                }\n            }\n\n            return null;\n        }\n\n        //internal virtual for testing purposes.\n        internal virtual void LoadModel()\n        {\n            var fs = WaitForFile(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read);\n            if (fs == null)\n                throw new IOException($\"Model file {_filePath} still got locked after 5 seconds, fail to reload.\");\n\n            using (fs)\n            {\n                _model = _context.Model.Load(fs, out _);\n            }\n        }\n\n        public void Dispose()\n        {\n            _watcher?.Dispose();\n        }\n\n        internal static class EventIds\n        {\n            public static readonly EventId FileReloadBegin = new EventId(100, \"FileReloadBegin\");\n            public static readonly EventId FileReloadEnd = new EventId(101, \"FileReloadEnd\");\n            public static readonly EventId FileReload = new EventId(102, \"FileReload\");\n            public static readonly EventId FileReloadError = new EventId(103, nameof(FileReloadError));","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.Extensions.ML/ModelLoaders/FileModelLoader.cs#L118-L154","documentation":"FileModelLoader.LoadModel opens the model file with a 5-second retry loop via WaitForFile; if the file remains locked by another process after 5 seconds it returns null and this IOException is thrown so the reload aborts instead of loading a partial or unreadable model. The ML.NET context never receives a stream, so _model keeps its previous value.","triggerScenarios":"Calling Start() or a file watcher change (WatcherChanged) triggering LoadModel() while the .zip model file is held open with an exclusive lock (FileShare incompatible with Read) for over 5 seconds.","commonSituations":"Another process (e.g. a trainer, backup/AV scanner, or an mlnet CLI training job) is still writing or holding the model file when the app hot-swaps it; copying the model over the same path without atomic rename; antivirus holding the file briefly after write.","solutions":["Ensure the producer writes the model atomically: write to a temp file and File.Move/replace onto the watched path so readers never see a locked file","Close the application or process holding an exclusive handle on the model file before triggering reload","Increase tolerance by retrying the load in your own code (catch IOException and call LoadModel again after a delay)","Exclude the model directory from antivirus real-time scanning"],"exampleFix":"// before: producer overwrites watched file directly\nmlContext.Model.Save(model, schema, File.Create(modelPath));\n// after: atomic replace\nvar tmp = modelPath + \".tmp\";\nusing (var fs = File.Create(tmp)) mlContext.Model.Save(model, schema, fs);\nFile.Move(tmp, modelPath, overwrite: true);","handlingStrategy":"retry","validationCode":"// before triggering reload\nvar fi = new FileInfo(modelPath);\nusing (var probe = fi.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) { } // throws IOException while locked","typeGuard":"bool IsFileReadable(string path) { try { using var _ = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read); return true; } catch (IOException) { return false; } }","tryCatchPattern":"try { loader.Start(); } catch (IOException ex) when (ex.Message.Contains(\"still got locked\")) { await Task.Delay(TimeSpan.FromSeconds(5)); retryLoad(); }","preventionTips":["Write model files atomically (temp file + rename)","Never keep handles open on files the watcher monitors","Exclude model dirs from AV/backup locking"],"tags":["io","file-locked","filesystem","reloading"],"backgroundTag":"file-open-failed","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}