If SaveConfig() does not save ini in UE 5.4

Conclusion

This symptom occurs in 5.4.1.

UCLASS with the config specifier applied is currently failing to create or save ini files in some cases.

There are two workarounds:

Way1. Add the string of “Editor” or “User” to the file name of the config

Like this. If your class is like this:

1
2
UCLASS(config = SomeConfigFileName)
class SOMEPROJECTNAME_API USomeClassName : public UObject

Change that like below.

1
2
UCLASS(config = SomeConfigFileNameUser) // Or it's ok with SomeConfigFileNameEditor
class SOMEPROJECTNAME_API USomeClassName : public UObject

Way 2. Manually create a config ini file and add the following content to the ini file

1
2
[SectionsToSave]
bCanSaveAllSections=true

Description

One of the goals of debugging this time was “to spend as little time as possible.”

Therefore, it is difficult for me to explain the exact cause in this post.

I ask for your understanding regarding this.

After I met the symptom that the ini file was not being saved properly, I was able to find the following forum post.

https://forums.unrealengine.com/t/5-4-config-not-saving-correctly/1860118

I also found a similar mention on Discord.

https://discord.com/channels/187217643009212416/846520322642411570/1240002393618256036

Keeping in mind that bCanSaveAllSections is close to the cause of the problem, I tried debugging the process of saving the ini file.

Along the way, I found the following code. This is code added in 5.4 that did not exist in 5.3.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    // check if the config file wants to save all sections
    bool bLocalSaveAllSections = false;
    // Do not report the read of SectionsToSave. Some ConfigFiles are reallocated without it, and reporting
    // logs that the section disappeared. But this log is spurious since if the only reason it was read was
    // for the internal save before the FConfigFile is made publicly available.
    const FConfigSection* SectionsToSaveSection = ConfigFile->FindSection(SectionsToSaveString);
    if (SectionsToSaveSection)
    {
      const FConfigValue* Value = SectionsToSaveSection->Find(SaveAllSectionsKey);
      if (Value)
      {
        const FString& ValueStr = UE::ConfigCacheIni::Private::FAccessor::GetValueForWriting(*Value);
        bLocalSaveAllSections = FCString::ToBool(*ValueStr);
      }
    }

    // we can always save all sections of a User config file, Editor* (not Editor.ini tho, that is already handled in the normal method)
    bool bIsUserFile = BaseIniName.Contains(TEXT("User"));
    bool bIsEditorSettingsFile = BaseIniName.Contains(TEXT("Editor")) && BaseIniName != TEXT("Editor");

    ConfigFile->bCanSaveAllSections = bLocalSaveAllSections || bIsUserFile || bIsEditorSettingsFile;

I was surprised to see string hardcoding here as well. It was hard to believe when I first saw it, and it’s still painful for me to accept. I am guessing that this was some decision that was added unavoidably while adding a new function that allows saving by section to ini. Anyway, as mentioned in a past post, string hardcoding seems to be used more often in engines than expected. This is something I want to keep in mind during future development.

tags