Initialization and settings
Installing the cfcore plugin does not start the SDK. FCFCoreModule::StartupModule registers the settings page and nothing else, so nothing works until your game initializes with an FCFCoreSettings. This page is that call, its teardown, and every settings field in cfcore-sdk-ue.
Settings come from an editor panel, for values that never change, and from a runtime USTRUCT, for values that vary per platform or must not ship in a config file. Most studios use both. For building and enabling the plugin see Installation; for the in-game UI see Mod browser.
Everything on this page covers cfcore, which initializes once per engine session through UCFCoreSubsystem, a UEngineSubsystem. If you also ship the mod browser, its UCFCoreUISubsystem is a separate, world-scoped subsystem with its own bring-up: InitializeUIController, then RegisterModelClass, before its widgets work. It reads the core subsystem internally and asserts if cfcore is not already initialized, so sequence the two: initialize cfcore first, per world, before calling InitializeUIController.
Where settings live
| Surface | Type | Where you edit it | Persisted to | Available in a packaged build |
|---|---|---|---|---|
| CFCore project settings panel | UCFCoreEditorSettings (UCLASS(config = Game, defaultconfig)) | Edit > Project Settings > Plugins > CFCore | Config/DefaultGame.ini | Yes, as the class default object. The panel itself is editor-only |
| Runtime settings struct | FCFCoreSettings (USTRUCT(BlueprintType)) | C++ or Blueprint, in your own init code | Nothing, you build it per run | Yes |
| Post-initialization patch | FCFCoreUpdatableSettings (USTRUCT(BlueprintType)) | C++ or Blueprint, after init succeeds | Nothing | Yes |
UCFCoreEditorSettings mirrors FCFCoreSettings field for field, with one difference: defaultLanguage defaults to en in the panel and to an empty string in the struct.
The panel class is config = Game, so entries are written to DefaultGame.ini in plaintext and shipped. Fine for a game id, a mods directory or a log setting. Wrong for the two premium keys and for initOptions.userContextId, which are config fields like every other. Leave those three empty in the panel and set them in code.
Every field on FCFCoreSettings and its eight nested structs is UPROPERTY(BlueprintReadWrite, EditAnywhere), so a Blueprint-only project reaches the whole surface through struct pins.
Building the settings struct
Neither make function carries a DisplayName meta, so the Blueprint label is Unreal's spaced form of the C++ name. Both are BlueprintPure, palette category cfcore.
| Method | Blueprint node | What it gives you | Use it when |
|---|---|---|---|
UCFCoreBPLibrary::MakeSettingsFromProjectConfig | Make Settings From Project Config | Every panel value copied into a runtime struct | The panel is your source of truth |
UCFCoreBPLibrary::MakeSettings | Make Settings | Only the six parameters below. Every other field keeps its struct default | You want a minimal explicit configuration, defaults elsewhere |
Fill FCFCoreSettings by hand | Set members in CFCoreSettings on the output of either node | Full control | Values vary per platform or per environment |
MakeSettings parameters, in order:
| Parameter | Type | Default |
|---|---|---|
default_language | const FString& | none |
game_id | int64 | none |
api_key | const FString& | none |
mods_directory | const FString& | none |
user_data_directory | const FString& | none |
max_concurrent_installations | int32 | 3 |
MakeSettings is meta=(NativeMakeFunc), the designated make node. Nothing exposes all fields, so set the rest through Set members in CFCoreSettings.
MakeSettings is not recommended as your primary path, since it only covers the six parameters above and leaves every other field at its struct default. Prefer MakeSettingsFromProjectConfig, or fill FCFCoreSettings by hand, unless a minimal explicit configuration is genuinely what you want.
Initializing the SDK
How it works
- Build an
FCFCoreSettings, from the panel or field by field. - Set
initOptions.userContextIdto the signed-in local player's identifier. - Call initialize. Five settings are validated synchronously and a missing one calls back with an error before any work happens.
- On passing validation the SDK stores the settings: it derives the API base URL from
gameId, resolves the directory escape tokens, appends the game id to the mods directory inCFCoremode, and re-clamps the file logger. This happens even if the rest of initialization then fails. - The user context, authentication, library and subscription services initialize in sequence, then the delegate fires.
- From then on, only
FCFCoreUpdatableSettingsfields change without a full uninitialize and re-initialize cycle.
#include <cfcore_context.h>
#include <editor/cfcore_bp_library.h>
// CFCoreContext and ICFCore live in namespace cfcore. FCFCoreSettings,
// FCFCoreError and the enums are declared at global scope.
using namespace cfcore;
void AMyGameMode::InitializeCurseForge() {
FCFCoreSettings settings = UCFCoreBPLibrary::MakeSettingsFromProjectConfig();
settings.isServer = true;
settings.isServerPcOnly = true;
// Required. Validation rejects an empty value.
settings.modsDirectory = TEXT("%USER_DIR%/my_game/mods");
settings.userDataDirectory =
TEXT("%USER_SETTINGS_DIR%/my_game/cfcore/user_data");
settings.modsDirectoryMode = EModsDirectoryMode::CFCore;
// Set in code, so it is never baked into DefaultGame.ini.
settings.initOptions.userContextId = TEXT("steam_76561198000000000");
settings.provider = ECFCoreExternalAuthProvider::Steam;
settings.logger.enabled = true;
settings.analytics.userEngagement = true;
CFCoreContext::GetInstance()->Initialize(
settings,
ICFCore::FInitializeDelegate::CreateUObject(
this, &AMyGameMode::OnCFCoreInitialized));
}
void AMyGameMode::OnCFCoreInitialized(TOptional<FCFCoreError> opt_err) {
if (opt_err.IsSet()) {
// MissingModsDirectory, MissingModsDirectoryMode,
// MissingUserDataDirectory, MissingGameId and MissingApiKey
// all arrive here.
UE_LOG(LogTemp, Error, TEXT("CFCore init failed: %s"),
*opt_err.GetValue().description);
}
}
Blueprint: get the subsystem with the engine's CFCore Subsystem accessor (search cfcoresu under Engine Subsystems, as described on Installation), then call Initialize: pins Target, Settings, OnInitialized, OnError. Feed Settings from Make Settings From Project Config (no input pins) or Make Settings. Both delegate pins are AutoCreateRefTerm, so an unwired pin still compiles.
The C++ delegate takes one TOptional<FCFCoreError>; the Blueprint node splits it into a result pin and a separate OnError pin. Paired success and error lambdas do not compile against the current SDK.
Required and validated settings
Validation stops at the first failure, in the order modsDirectory, modsDirectoryMode, userDataDirectory, gameId, apiKey, so fixing one can reveal the next.
| Setting | Required | Error when missing or invalid |
|---|---|---|
modsDirectory | Yes, must be non-empty | ECFCoreErrorCodes::MissingModsDirectory |
modsDirectoryMode | Yes, must not be EModsDirectoryMode::None | ECFCoreErrorCodes::MissingModsDirectoryMode |
userDataDirectory | Yes, must be non-empty | ECFCoreErrorCodes::MissingUserDataDirectory |
gameId | Yes, must be greater than zero | ECFCoreErrorCodes::MissingGameId |
apiKey | Yes, must be non-empty | ECFCoreErrorCodes::MissingApiKey |
| Everything else | Optional | None |
Confirm both gameId and apiKey against your game record, see Setting up your game.
Checking state and tearing down
| Purpose | C++ | Blueprint node |
|---|---|---|
| Query whether the SDK is initialized | ICFCore::IsInitialized | None. Latch a boolean off Initialize's OnInitialized and OnError pins |
Tear down so a new FCFCoreSettings can be applied | ICFCore::Uninitialize | Uninitialize, pins OnUninitialized and OnError |
Tearing down when the SDK was never initialized returns success with an unset error. FCFCoreModule::ShutdownModule also calls it, so module unload tears the SDK down whether or not your game asked.
A second initialize call is not rejected. ECFCoreErrorCodes::AlreadyInitialized is declared on the error enum but never returned anywhere in the plugin, and the initialize path has no guard: a second call re-runs the sequence and silently replaces the resolved directories and API host. Uninitialize first and gate on IsInitialized.
Changing settings after initialization
FCFCoreUpdatableSettings is the entire post-initialization surface, and defaultLanguage is the only setting on it.
| Field | Type | Default | What it controls |
|---|---|---|---|
updateDefaultLanguage | bool | false | Whether to apply defaultLanguage from this struct to the live settings |
defaultLanguage | FString | Empty | The new language value. Empty is valid and clears the ?lang= query parameter |
updateDefaultLanguage is a presence marker, not a toggle: with it false the value is ignored, and with an unchanged value nothing is broadcast.
void AMyGameMode::SetCurseForgeLanguage(const FString& language_code) {
FCFCoreUpdatableSettings updatable;
updatable.updateDefaultLanguage = true;
updatable.defaultLanguage = language_code; // "" clears the lang parameter
CFCoreContext::GetInstance()->UpdateSettings(
updatable,
ICFCore::FUpdateSettingsDelegate::CreateLambda(
[](TOptional<FCFCoreError> opt_err) {
if (opt_err.IsSet()) {
// FailedToInitialize means the SDK was not initialized yet.
}
}));
}
Blueprint: call Update Settings on the subsystem: pins InSettings (an FCFCoreUpdatableSettings), OnSuccess and OnError, both AutoCreateRefTerm.
Calling it before initialization completes returns ECFCoreErrorCodes::FailedToInitialize, the same code as a genuine initialization failure. Gate on IsInitialized, or on your latched Blueprint flag, instead of inferring from the error.
Everything else needs an uninitialize and re-initialize, which re-resolves the directory paths: a changed modsDirectory, modsDirectoryMode, gameId or userDataDirectory relocates where the SDK looks.
Settings reference
Field names are the literal FCFCoreSettings members, which are the panel labels once Unreal spaces them (maxConcurrentInstallations shows as Max Concurrent Installations).
| Field | Type | Default | Required | What it controls |
|---|---|---|---|---|
initOptions | FCFCoreInitializationOptions | Default-constructed | Optional, set in practice | Options passed by the game at initialization |
defaultLanguage | FString | Empty (en in the panel) | Optional | Appended as ?lang= to API calls that support it. Empty omits the parameter. The only setting changeable after init |
gameId | int64 | 0 | Required | Your game id. Also builds the API base URL, and is the folder appended to modsDirectory in CFCore mode |
apiKey | FString | Empty | Required | Your game API key. Sent as the x-api-key header on every request when non-empty |
provider | ECFCoreExternalAuthProvider | None | Optional | The store or platform the build runs on. Sent as the x-provider header when not None |
maxConcurrentInstallations | int32 | 3 (cfcore::kCFCoreDefaultMaxConcurrentInstallation) | Optional | How many mod installations run at once. Clamped to a minimum of 1 |
modsDirectory | FString | Empty | Required | Where extracted mods are written. Supports the escape tokens below |
modsDirectoryMode | EModsDirectoryMode | CFCore | Required, None rejected | On-disk layout under modsDirectory |
userDataDirectory | FString | Empty | Required | Where user state (enabled mods, auth token) and log files are written. Same escape tokens |
isServer | bool | false | Optional | Game server build: _server is appended to the platform header value and x-mod-server-request: true is added. Must be true before Assure Server Mods Updated |
isServerPcOnly | bool | false | Optional | Read only when isServer is true. Set it if the server accepts PC clients only, so server-library file matching filters to PC |
throttling | FCFCoreSettingsThrottling | Struct default | Optional | Disk IO throttling |
premiumMods | FCFCoreSettingsPremiumMods | Struct default | Optional | Signature and decryption keys for paid mods |
logger | FCFCoreSettingsLogger | Struct default | Optional | On-disk log files |
dynamicContentCategoryIds | TSet<int64> | Empty | Optional | Category ids that mark a mod as dynamic content. An installed mod joins the premium ownership check when one of its category ids is in this set and it is not already flagged dynamicContent |
analytics | FCFCoreSettingsAnalytics | Struct default | Optional | Which analytics categories the SDK may send |
ignoredDynamicModFiles | TSet<FString> | { "assetregistry.bin" } | Optional | Filenames excluded from fingerprint and total-size calculation, for files created at runtime that are not part of the mod |
unmanagedMods | FCFCoreSettingsUnmanagedMods | Struct default | Optional | Detection of mods not installed through the plugin |
subscriptions | FCFCoreSettingsSubscriptions | Struct default | Optional | Cross-device subscription sync and automatic management |
downloads | FCFCoreSettingsDownloads | Struct default | Optional | Chunked download parallelism |
ignoredDynamicModFiles is matched against the lowercased clean filename, not a path, so entries must be lowercase bare filenames. MyFile.BIN never matches, myfile.bin does.
The dynamicContentCategoryIds check runs the opposite way round from most expectations. A mod already flagged dynamicContent is excluded from the ownership check, on the assumption the player has not installed it yet. The category set adds installed mods your game treats as dynamic content by category into the check.
Initialization options
FCFCoreInitializationOptions, nested at FCFCoreSettings::initOptions, carries one field.
| Field | Type | Default | What it controls |
|---|---|---|---|
userContextId | FString | Empty | Determines the path to the local user information file |
| Platform | What to pass | Example |
|---|---|---|
| Consoles | The currently signed-in username or user identifier | psn_3165746192837465 (PSN account id), xbl_2535465299942153 (Xbox XUID) |
| PC | The currently signed-in Steam or EOS username or user identifier | steam_76561198043211234 |
An empty userContextId becomes the literal string local, in both the user context service and the installed-mods user service. That works for a single-profile PC build and is wrong everywhere else: two players on the same console then share one context, so one player's installed-mod state and auth token become the other's. Set it in code, since a panel value ships in the ini and gives every player the same id.
Provider values
provider takes an ECFCoreExternalAuthProvider, the same enum used for external authentication. Setting it here only determines the x-provider header sent with SDK requests, it does not require Developer Portal setup. Portal setup is required separately for external authentication itself: see Authentication overview and Silent authentication.
| Value | Numeric | Notes |
|---|---|---|
None | 0 | No provider header is sent |
Steam | 1 | Session ticket from ISteamUser::GetAuthSessionTicket, base64-encoded as the external token |
PSN | 2 | PlayStation Network. Access token obtained from an authorization code |
XBL | 3 | Xbox Live. Access token obtained using an XSTS token |
WB | 4 | Warner Brothers |
Epic | 5 | Epic Games. JWT from EOS_Auth_CopyIdToken, passed as the external token |
GOG | 6 | GOG Galaxy. Encrypted app ticket from galaxy::api::User()->RequestEncryptedAppTicket(), base64-encoded. Needs the Encrypted App Ticket Key configured in your game's authentication section |
Those seven are the whole enum in the current release.
Mods directory mode
| Value | Numeric | Resulting layout | Notes |
|---|---|---|---|
None | 0 | n/a | Rejected by validation with MissingModsDirectoryMode. The unset state, not a usable mode |
CFCore | 1 | [modsDirectory]/[gameId]/[modId]_[fileId]/ | The default. The SDK inserts the game id folder, and each mod gets its own [modId]_[fileId] folder |
Flat | 2 | [modsDirectory]/ | Mod contents go directly under the configured directory |
Because CFCore mode appends gameId, changing the game id moves the mods directory. Two configurations with different game ids on the same modsDirectory produce sibling trees, not a collision.
Pointing Flat at the game's own mods folder is discouraged: you can lose control over which mods are enabled or disabled, and over premium mods, if you also run Unreal's own mods APIs against that folder. Read the per-mod path from the installed-mod record's pathOnDisk rather than reconstructing it.
Directory escape tokens
modsDirectory and userDataDirectory accept four tokens, resolved when settings are stored at initialization and whenever they are re-applied.
| Token | Constant | Resolves to |
|---|---|---|
%USER_DIR% | cfcore::kSpecialFolderUserDirectory | FPlatformProcess::UserDir() |
%USER_SETTINGS_DIR% | cfcore::kSpecialFolderUserSettingsDirectory | FPlatformProcess::UserSettingsDir() |
%PROJECT_DIR% | cfcore::kSpecialFolderProjectDirectory | FPaths::ProjectDir() |
%PROJECT_SAVED_DIR% | cfcore::kSpecialFolderProjectSavedDirectory | FPaths::ProjectSavedDir() |
Matching is case-insensitive and tokens work anywhere in the string. After substitution the path goes through FPaths::MakeStandardFilename and doubled forward slashes collapse to one. These four are the whole set: an unrecognised %TOKEN% is left verbatim and becomes a literal folder name.
Sub-settings reference
analytics
FCFCoreSettingsAnalytics. Server-side feature flags apply on top of these, so a category can be suppressed even when you enable it. For category contents see Analytics data collection.
| Field | Type | Default | What it controls |
|---|---|---|---|
performanceAndStability | bool | true | Success and failure rates for install, update and manage. Collected by the SDK automatically when enabled |
userEngagement | bool | false | In-game player behaviour: mod browser funnels and engagement with mods |
userEngagement does not by itself produce funnel or session data. Nothing in cfcore calls the three public analytics methods, so those events come from calls in your game: Send Game Play Session Analytic, Send Mod Browsing Funnel Impression Analytic, Send Mod Browsing Funnel Action Analytic. The category check reads the live settings object, populated only during initialization, so call them after init succeeds. A call in a disabled category returns true and sends nothing, so a successful return is not evidence an event was sent. One User Engagement event is the exception and is sent by the SDK itself: see Analytics.
downloads
| Field | Type | Default | Valid range | What it controls |
|---|---|---|---|---|
maxParallelChunks | int32 | 1 | 1 to 32, enforced by ClampMin/ClampMax in the panel | Maximum chunks downloaded in parallel |
FCFCoreSettingsDownloads::maxParallelChunks is ignored for any installation whose FInstallModAdditionalParams::throttleDownloadKbps is greater than 0: that install downloads one chunk at a time. The default of 1 means chunked downloads are sequential unless you raise it.
logger
FCFCoreSettingsLogger. Plugin logs go through UE_LOG, which most shipping games do not write to disk, and these logs are what makes a player-side install failure diagnosable. This struct adds an on-disk log in a logs subfolder of the resolved userDataDirectory.
| Field | Type | Default | Effective range at runtime | What it controls |
|---|---|---|---|---|
enabled | bool | false | n/a | Write logs to local disk |
history | int32 | 8 | Clamped to 0 to 30 | Number of rolled log files kept on disk |
maxSizeInMB | int32 | 2 | Clamped to 2 to 10 | Maximum size of a single log file before it rolls |
premiumMods
FCFCoreSettingsPremiumMods. Relevant only if your game sells paid mods, which has to be enabled on your game record first: contact cfforstudios@overwolf.com.
| Field | Type | Default | What it controls |
|---|---|---|---|
publicKeyPem | FString, multi-line in the panel | Empty | RSA public key in PEM format, used to verify the signature the server returns when verifying the player's owned mods |
privateKeyPem | FString, multi-line in the panel | Empty | RSA private key in PEM format, used to decrypt the guid and key pairs returned by the premium mod file details call |
Both keys depend on CFCORE_WITH_OPENSSL, defined by default in the plugin's crypto service. Remove OpenSSL from PrivateDependencyModuleNames in cfcore.Build.cs and comment out that define, and signature verification returns true unconditionally while RSA decryption becomes impossible: publicKeyPem verifies nothing and privateKeyPem cannot decrypt.
subscriptions
FCFCoreSettingsSubscriptions. Subscriptions let a player manage their mod list across devices: subscribe on one device, install automatically on the others.
| Field | Type | Default | Valid range | What it controls |
|---|---|---|---|---|
automaticModManagementIntervalMs | int32 | 30000 | 10000 to 600000, enforced by ClampMin/ClampMax in the panel | Interval between automatic mod management runs. Read when automatic management is enabled |
allowInstallActions | bool | true | n/a | Permit install actions in sync plans and automatic management |
allowUninstallActions | bool | true | n/a | Permit uninstall actions in sync plans and automatic management |
allowUpdateActions | bool | true | n/a | Permit update actions in sync plans and automatic management |
autoSubscribeInstalledMods | bool | false | n/a | On the first login after initialization, subscribe the player to any locally installed managed mod not yet in their server-side subscription list |
Subscriptions must be enabled for your game on the Developer Portal at console.curseforge.com, or the calls made by autoSubscribeInstalledMods fail with HTTP errors. Contact cfforstudios@overwolf.com.
autoSubscribeInstalledModsruns off the login response, only when the user context does not already record that it has run, and never again for that player.- The three
allow*flags are read per action when a sync plan is built, not once at initialization, so a mid-session change affects the next plan. - Automatic management caches
automaticModManagementIntervalMswhen enabled. Calling Enable Auto Management while it is already enabled restarts it, which is how a changed interval takes effect. - With
unmanagedMods.enabledtrue, an installed mod flaggedunmanagedis skipped by sync. A mod flagged as dynamic content is skipped unconditionally. - Automatic management is not for active gameplay. Run it in menus, a launcher, or a web-style UI, where an install, update or uninstall cannot collide with content the game is using. For a lower-risk posture, leave it on with only
allowUpdateActionsenabled.
throttling
FCFCoreSettingsThrottling. The panel description is blunt: IO throttling is not something to use unless you know what you are doing.
| Field | Type | Default | What it controls |
|---|---|---|---|
diskWriteBytesPerSec | int64 | 0 | Bytes written to disk per second. 0 means no limit |
Only 0 disables throttling. Any non-zero value is floored at 2621440 bytes per second (2.5 MB/s), so 100000 gives you 2.5 MB/s, not 100 KB/s.
unmanagedMods
FCFCoreSettingsUnmanagedMods. Unmanaged mods sit in the player's mods directory without having been installed through the plugin, usually because they do not exist on CurseForge yet. The intended use is letting mod authors play with their own work before uploading it.
| Field | Type | Default | What it controls |
|---|---|---|---|
enabled | bool | false | Detect unmanaged mods in the mods directory and treat each as an installed unmanaged mod. The field on the installed-mod record is unmanaged |
scanOneLevelUp | bool | false | Run a second scan rooted at the configured modsDirectory, with the game id subfolder excluded |
scanOneLevelUp only makes sense in CFCore mode, where one level up from the scanned directory is the root a mod author is most likely to have used. The implementation checks the flag, not the directory mode: in Flat mode the root and the scanned directory are the same and the excluded subfolder is empty, so the second scan walks the same tree again and appends the results. Leave it off in Flat mode.
Keeping keys out of the ini file
Both premium keys have a runtime setter that bypasses the project settings, so the key never lands in DefaultGame.ini.
| Purpose | C++ | Blueprint node |
|---|---|---|
| Signature verification key | ICFCorePremiumMods::OverridePublicKey | Override Public Key |
| Decryption key for premium mod file details | ICFCorePremiumMods::OverridePrivateKey | Override Private Key |
// Supply the keys from wherever your build injects secrets, not from the ini.
CFCoreContext::GetInstance()->PremiumMods()->OverridePublicKey(public_key_pem);
CFCoreContext::GetInstance()->PremiumMods()->OverridePrivateKey(private_key_pem);
Blueprint: Override Public Key takes InPublicKeyPem, OnSuccess, OnError; Override Private Key takes InPrivateKeyPem, OnSuccess, OnError. Unlike the lifecycle nodes these two do not declare AutoCreateRefTerm, so wire both delegate pins. The C++ methods take only the PEM string and return void, so expect no completion callback there.
A private key, from the override or from privateKeyPem, is required for Get Premium Mod File Details to decrypt the guid and key pairs, which otherwise fails with ECFCoreErrorCodes::FailedToDecrypt. Generate an RSA 2048 pair, set the private key on the Developer Portal at console.curseforge.com under UGC Monetization, and keep the public key on the client.
The SDK masks apiKey, premiumMods.publicKeyPem and premiumMods.privateKeyPem when it logs the settings object, as ***** plus the last four characters. Only those three are masked.
Values the SDK adjusts at runtime
An out-of-range value does not produce an error, it produces different behaviour than you configured.
| Setting | Configured value | What the SDK uses |
|---|---|---|
maxConcurrentInstallations | 0 or negative | 1 |
logger.history | Below 0 / above 30 | 0 / 30 |
logger.maxSizeInMB | Below 2 / above 10 | 2 / 10 |
throttling.diskWriteBytesPerSec | Non-zero and below 2621440 | 2621440 (2.5 MB/s) |
downloads.maxParallelChunks | Any value, when a per-install download throttle is set | One chunk at a time |
initOptions.userContextId | Empty | The literal string local |
modsDirectory | Any value, in CFCore mode | modsDirectory with gameId appended as a folder |
defaultLanguage | Empty | The ?lang= parameter is omitted rather than sent empty |
provider | None | No x-provider header is sent |
isServer | true | _server appended to the platform header value, unless it already ends with server |
The ClampMin and ClampMax metadata constrains the editor panel only. A value assigned in C++ or Blueprint is not clamped, so respect the documented ranges in code.
Configuration error codes
Each code is a member of ECFCoreErrorCodes, arriving as an FCFCoreError whose fields are isError, code, apiError and description.
| Code | When you get it | What to do |
|---|---|---|
MissingModsDirectory | modsDirectory is empty at initialization | Set it, with or without escape tokens |
MissingModsDirectoryMode | modsDirectoryMode is None at initialization | Set CFCore or Flat |
MissingUserDataDirectory | userDataDirectory is empty at initialization | Set it |
MissingGameId | gameId is 0 or negative at initialization | Set it. Confirm the value against your game record |
MissingApiKey | apiKey is empty at initialization | Set it. Confirm the value against your game record |
FailedToInitialize | Returned by the settings update path when the SDK is not initialized | Initialize first, then update. Not a validation failure |
AlreadyInitialized | Never. Declared on the enum, not returned anywhere in the plugin | Nothing. Track initialization yourself and uninitialize before initializing again |
FileSystemError | User context initialization failed: the user context file under userDataDirectory could not be created or read, or the shared context failed. Also returned by the user-state persistence paths | Check that the resolved userDataDirectory is writable on the target platform |
FailedToDecrypt | Premium mod file details could not be decrypted | Supply premiumMods.privateKeyPem or call Override Private Key, and confirm the build still has OpenSSL |
Getting help
Anything that must be enabled on your game record before a setting does anything (premium mods, subscriptions, mods highlights, a provider that needs authentication setup) is managed on the Developer Portal at console.curseforge.com. For enablement requests and engine version certification, contact cfforstudios@overwolf.com.