{"record":{"id":"50b4c03ea2358f33","repo":"dotnet/machinelearning","slug":"start-must-be-called-on-a-modelloader-before-it-ca","errorCode":null,"errorMessage":"Start must be called on a ModelLoader before it can be used.","messagePattern":"Start must be called on a ModelLoader before it can be used\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.Extensions.ML/ModelLoaders/FileModelLoader.cs","lineNumber":97,"sourceCode":"                    Logger.ReloadingFile(_logger, _filePath, timer.Elapsed);\n                }\n                previousToken.OnReload();\n                timer.Stop();\n                Logger.FileReloadEnd(_logger, _filePath, timer.Elapsed);\n            }\n            catch (OperationCanceledException)\n            {\n                // This is a cancellation - if the app is shutting down we want to ignore it.\n            }\n            catch (Exception ex)\n            {\n                Logger.FileReloadError(_logger, _filePath, timer.Elapsed, ex);\n            }\n        }\n\n        public override IChangeToken GetReloadToken()\n        {\n            if (_reloadToken == null) throw new InvalidOperationException(\"Start must be called on a ModelLoader before it can be used.\");\n            return _reloadToken;\n        }\n\n        public override ITransformer GetModel()\n        {\n            if (_model == null) throw new InvalidOperationException(\"Start must be called on a ModelLoader before it can be used.\");\n\n            return _model;\n        }\n\n        private FileStream WaitForFile(string fullPath, FileMode mode, FileAccess access, FileShare share)\n        {\n            for (int numTries = 0; numTries < 100; numTries++)\n            {\n                FileStream fs = null;\n                try\n                {\n                    fs = new FileStream(fullPath, mode, access, share);","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.Extensions.ML/ModelLoaders/FileModelLoader.cs#L79-L115","documentation":"FileModelLoader.GetReloadToken throws InvalidOperationException because the loader has not been initialized by a call to Start. Start creates the _reloadToken (and _model) lazily; before that, these members are null and there is no change token to hand out. The library treats using an un-started loader as a programming error in the host application.","triggerScenarios":"Calling GetReloadToken() (directly or via a ChangeToken registration/OnChange subscription) before FileModelLoader.Start() has completed; resolving a ModelLoader from DI where only the loader was registered but Start was never invoked at startup.","commonSituations":"Custom startup code registering the loader but skipping Start(); DI service resolving the loader earlier than the hosted service that calls Start; race where an OnChange callback fires before initialization; refactoring away the hosted-service bootstrap that used to call Start.","solutions":["Call Start() on the FileModelLoader before any consumer accesses GetReloadToken(), typically during application startup (e.g. in Program.cs or a hosted service).","If using the Microsoft.Extensions.ML abstractions, register the loader via the standard AddPredictionEnginePool/ModelLoader pipeline so Start is called automatically.","If ordering is the issue, resolve the loader inside a hosted service that explicitly calls Start before subscribing to reload tokens.","Alternatively switch to DirectoryModelLoader-based registration which manages lifecycle for you."],"exampleFix":"// before\nvar loader = new FileModelLoader(logger, modelPath);\nvar token = loader.GetReloadToken(); // InvalidOperationException\n// after\nvar loader = new FileModelLoader(logger, modelPath);\nloader.Start();\nvar token = loader.GetReloadToken();\nChangeToken.OnChange(() => loader.GetReloadToken(), () => ReloadPredictor());","handlingStrategy":"try-catch","validationCode":"if (loader is FileModelLoader fml && !fml.IsStarted)\n    fml.Start();\nvar token = loader.GetReloadToken();","typeGuard":null,"tryCatchPattern":"try\n{\n    var token = loader.GetReloadToken();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Start must be called\"))\n{\n    loader.Start();\n    var token = loader.GetReloadToken();\n}","preventionTips":["Call Start() during application startup before any code reads reload tokens or models","Use the standard Microsoft.Extensions.ML DI abstractions so lifecycle is managed for you","Enforce ordering with a hosted service that starts the loader before other components resolve it","Add an integration test that resolves the loader as DI would and asserts GetReloadToken works"],"tags":["mlnet","invalid-state","lifecycle","model-loading","dotnet"],"backgroundTag":"invalid-state-transition","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}