Conversation
The server crashed when the database schema existed but the game configuration was missing, e.g. after a failed data import: * The reference handler factory dereferenced the default game configuration id without checking for null. * The plugin configuration factory tried to create the missing plugin configurations and called First() on an empty game configuration set. Both cases are now handled gracefully, so the server starts up and the admin panel offers to install the data. Because the plugin configurations only exist after the data initialization, they are now read into the PlugInManager when the database gets initialized, before the server containers are restarted. The setup page now shows the same "Create" action as for a non-existing database when the data isn't initialized, and refreshes its state after an installation. Closes #908 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SF8VVTJtUjimJfVKa32Lxm
sven-n
commented
Sep 22, 2026
sven-n
left a comment
Member
Author
There was a problem hiding this comment.
The startup fix works: an empty database no longer crashes the server. The follow-up after an install has problems, though:
- Plugin configurations fail after an install.
PlugInManagerkeeps the reference handler it got at startup, whose data source never loaded a game configuration. The first custom configuration with a reference throws and stops the loop (seeProgram.cs:423). - The new "Create" button wipes the database without asking.
IsDataInitializedAsyncreturnsfalseon a timeout or error, so a populated database can land on this branch (seeSetup.razor:36). - This handler doesn't finish before the servers restart. The multicast
AsyncEventHandleronly returns the last subscriber's task, so the handler racesRestartAllAsync(seeProgram.cs:344).
The rest are smaller follow-ups and nits.
Generated by Claude Code
* The data source of the plugin manager's reference handler is reloaded when the database got initialized. Otherwise, the references of the custom plugin configurations were resolved on a data source which was either not loaded at all (empty database) or holds the previous, deleted game configuration (re-install). * The plugin configurations are taken from that reloaded data source, so they stay alive as long as the reference handler does. The registered collection of plugin configurations is updated as well. * A failing plugin configuration doesn't stop the remaining ones from being read anymore. * Reading the configurations again can now also activate a plugin, which is required when it was inactive in the previously read data. * Previously read configurations are not observed anymore when they are read again, so the property changed handlers don't pile up. * SetupService.CreateDatabaseAsync awaits the subscribers of its DatabaseInitialized event one after another. A multicast delegate only returns the task of the last subscriber, so the plugin configurations were applied while the server containers were already restarting. * The setup page only offers to create the data without a confirmation when it knows for sure that the database contains no game configuration. A failed or timed out check is reported as unknown state now, which keeps the confirmed re-install button. The state is also determined again after a schema update, because it can't be determined on an outdated schema. * The setup page loads the state before it hides the installer, so it doesn't show the state of the uninitialized database for a moment. * Removed the redundant game configuration check in the plugin configuration factory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SF8VVTJtUjimJfVKa32Lxm
Resolved the conflicts in the setup page: master moved the SetupService to the persistence project and added the backup/snapshot sections, while this branch replaced the _isDataInitialized flag by the tri-state DataInitializationState. The enum moved to the persistence project as well, so that it stays next to the SetupService. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SF8VVTJtUjimJfVKa32Lxm
Deploying openmudocs with
|
| Latest commit: |
c807ca4
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://7e3ea4b6.openmudocs.pages.dev |
| Branch Preview URL: | https://claude-issue-908-vwkrug.openmudocs.pages.dev |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #908.
When the database schema exists but the
GameConfigurationis missing (e.g. after a failed import), the Startup project crashed while building the host.Root causes
Program.CreateHostAsync: theByDataSourceReferenceHandlerfactory dereferenced the default game configuration id (configId!.Value) without a null check →NullReferenceException. It's resolved while constructing thePlugInManagersingleton, so the host never started.Program.CreateMissingPlugInConfigurations:context.GetAsync<GameConfiguration>()...First()threw anInvalidOperationException, becausePlugInConfigurationsFactoryalways tries to create the plugin configurations it finds missing — which is all of them on an empty database.Changes
Startup
Startup/Program.cs: both paths handle a missing game configuration now. The configuration context in the reference handler factory is disposed properly, too.PlugInManagersingleton starts without plugin configurations.Programsubscribes toSetupService.DatabaseInitialized(before the host, and with it the server containers, is started) and reads the created plugin configurations afterwards.ICollection<PlugInConfiguration>is updated as well.Plugin manager
ReadConfigurations(IEnumerable<PlugInConfiguration>), which can be called again when the configurations become available later.PropertyChangedhandlers don't pile up.Setup service and page
SetupService.CreateDatabaseAsyncawaits the subscribers of itsDatabaseInitializedevent one after another. A multicast delegate only returns the task of the last subscriber, so the plugin configurations were applied while the server containers were already restarting.DataInitializationState(Initialized,NotInitialized,Unknown) tells a failed or timed out check apart from an actually empty database. The setup page only offers the unconfirmed Create button forNotInitialized;Unknownkeeps the confirmed ReInstall button.Testing
MUnique.OpenMU.Tests(984),MUnique.OpenMU.Web.Tests(95),MUnique.OpenMU.PlugIns.Tests(41),MUnique.OpenMU.ChatServer.Tests(26) andMUnique.OpenMU.Persistence.Initialization.Tests(21, 6 skipped) pass.Generated by Claude Code