LorisYounger/VPet · error · Exception
Save data is null
Error message
Save data is null
What it means
MainWindow.Save serializes GameSavesData to LPS and asserts the resulting string is non-null before writing the save file, throwing a generic Exception if it is null. This is a defensive invariant protecting the save routine from silently writing nothing.
Solutions
- Ensure GameSavesData is initialized before Save/autosave can run (guard AutoSaveTimer start until data load completes).
- Verify ToLPS()/ToString() never returns null (return empty LPS instead).
- Skip the save when GameSavesData is null and log instead of throwing, so window close isn't blocked.
- Repair or delete the corrupt save that produced a null model, then let the game recreate it.
Example fix
// before
var savesdata = saveslps.ToString();
if (savesdata == null)
throw new Exception("Save data is null");
// after
if (GameSavesData == null) return; // nothing to save yet
var savesdata = saveslps?.ToString() ?? string.Empty; Defensive patterns
Strategy: try-catch
Validate before calling
if (GameSavesData == null) { /* skip save */ } Type guard
bool CanSave() => GameSavesData != null && GameSavesData.ToLPS() != null;
Try / catch
try { Save(); } catch (Exception ex) when (ex.Message == "Save data is null") { Log.Warn("save skipped: no game data loaded yet"); } Prevention
- Start the autosave timer only after game data is fully loaded
- Initialize GameSavesData with an empty model instead of null
- Never throw from Window_Closed handlers; log and degrade gracefully
When it happens
Trigger: Save (called by Restart_Closed, AutoSaveTimer_Elapsed, Window_Closed) runs while GameSavesData.ToLPS() yields a null string — effectively a null/degenerate save data model.
Common situations: Autosave timer firing before the game data model was initialized; closing the window during early startup before GameSavesData is populated; corrupted/missing save data loaded as null.
AI-assisted analysis of LorisYounger/VPet@ffb9cc2a85 (2026-09-15).
Data as JSON: /api/errors/902c79ab4de0e349.
Report an issue: GitHub.
Appendix: source
Thrown at VPet-Simulator.Windows/MainWindow.cs:327
var ds = new List<string>(Directory.GetFiles(ExtensionValue.BaseDirectory + @"\Saves", $"Save{PrefixSave}_*.lps")).OrderBy(x =>
{
if (int.TryParse(x.Split('_').Last().Split('.')[0], out int i))
return i;
return 0;
}).ToList();
while (ds.Count > Set.BackupSaveMaxNum)
{
File.Delete(ds[0]);
ds.RemoveAt(0);
}
if (File.Exists(ExtensionValue.BaseDirectory + $"\\Saves\\Save{PrefixSave}_{st}.lps"))
File.Delete(ExtensionValue.BaseDirectory + $"\\Saves\\Save{PrefixSave}_{st}.lps");
var saveslps = GameSavesData.ToLPS();
var savesdata = saveslps.ToString();
if (savesdata == null)
throw new Exception("Save data is null");
int hash = Math.Abs(saveslps.GetHashCode() % 255);
if (File.Exists(ExtensionValue.BaseDirectory + $"\\Saves_BKP\\Save{PrefixSave}_{hash:X}.lps"))
File.Delete(ExtensionValue.BaseDirectory + $"\\Saves_BKP\\Save{PrefixSave}_{hash:X}.lps");
//存档
File.WriteAllText(ExtensionValue.BaseDirectory + $"\\Saves\\Save{PrefixSave}_{st}.lps", savesdata);
//备份
File.WriteAllText(ExtensionValue.BaseDirectory + $"\\Saves_BKP\\Save{PrefixSave}_{hash:X}.lps", savesdata);
if (File.Exists(ExtensionValue.BaseDirectory + @"\Save.lps"))
{
if (File.Exists(ExtensionValue.BaseDirectory + @"\Save.bkp"))
File.Delete(ExtensionValue.BaseDirectory + @"\Save.bkp");
File.Move(ExtensionValue.BaseDirectory + @"\Save.lps", ExtensionValue.BaseDirectory + @"\Save.bkp");
}
View on GitHub (pinned to ffb9cc2a85)