Skip to content

Does Save Game Exist / Delete Game in Slot / Async Save Game to Slot

At a glance

Lives in: Blueprint API / SaveGame; implemented by Gameplay Statics and an async action object - Returns: existence/delete success Booleans; async save fires a Completed pin with Success and the SaveGame object - Fails by: returning false, completing with Success = false, or racing another save/load request - Official docs: Does Save Game Exist, Delete Game in Slot, Async Save Game to Slot, and Save Game

The one-minute version

  • Does Save Game Exist checks whether a named slot exists for the given user index. It returns true or false.
  • Delete Game in Slot attempts to delete a slot. Its return value means the file was actually deleted; use the existence check to tell "missing" from "delete failed."
  • Async Save Game to Slot schedules a save and continues later from Completed with a Success Boolean.
  • Slot name and user index must match across check, load, save, and delete.
  • Async save is still your responsibility: do not start overlapping saves and then assume the last widget click wins.
  • These nodes do not serialize live actor references, choose what data belongs in a save, or freeze the world while a save finishes.

What they actually do

SaveGame slots are files managed by Unreal's platform save system:

flowchart LR
    World[Live world actors] --> Copy[Copy plain values]
    Copy --> SaveObj[SaveGame object]
    SaveObj --> Slot[SlotName + UserIndex]

The utility nodes operate on that slot identity:

pseudocode of the engine behavior - not engine source

function DoesSaveGameExist(SlotName, UserIndex):
    return platform save system has data for SlotName/UserIndex

function DeleteGameInSlot(SlotName, UserIndex):
    if no save data can be deleted:
        return false
    delete the saved data
    return true

function AsyncSaveGameToSlot(SaveGameObject, SlotName, UserIndex):
    schedule save work
    later:
        Completed(SaveGameObject, Success)

The important part is still manual: copy durable values into the SaveGame object before saving, and copy them back into live actors after loading.

When they fail (and what failure does)

Common causes:

  1. Slot name mismatch. "Save01", "save01", and "Slot1" are different names for your Blueprint logic.
  2. Wrong user index. Many beginner projects use 0, but platforms can treat users differently. Be consistent.
  3. The slot does not exist. Does Save Game Exist returns false; loading should create defaults instead of assuming a file exists.
  4. Delete returned false because nothing existed. Check existence first if your UI needs to distinguish "already empty" from "delete failed."
  5. The SaveGame object is None or the wrong class. Async save needs the object that contains your data.
  6. Overlapping requests race. A load and save at the same time, or two rapid saves to the same slot, can produce platform-dependent behavior.
  7. You saved live references. Actor, widget, controller, component, and level references are not durable save data.

Failure does not throw an exception in Blueprint. You get false or Success = false, and the graph should keep the menu disabled, show an error, or retry through a deliberate path.

The pattern everyone actually uses

Startup load-or-create:

BeginPlay / menu start
-> Does Save Game Exist("Profile0", 0)
-> Branch
    true: Load Game From Slot
    false: Create Save Game Object BP_SaveProfile
-> Cast To BP_SaveProfile
-> copy values into GameInstance / player setup

Manual save button:

Save button clicked
-> disable save button / show saving state
-> copy current plain values into BP_SaveProfile
-> Async Save Game to Slot("Profile0", 0)
-> Completed
-> Branch Success
-> re-enable button / show saved or failed state

Delete slot:

Confirm Delete
-> Does Save Game Exist("Profile0", 0)
-> Branch
    false: update menu as empty
    true: Delete Game in Slot
-> Branch Return Value
-> clear UI row or show delete failed

The C++ twin, for the curious (our own example code):

void USaveMenu::DeleteProfile()
{
    constexpr int32 UserIndex = 0;
    const FString SlotName = TEXT("Profile0");

    if (!UGameplayStatics::DoesSaveGameExist(SlotName, UserIndex))
    {
        MarkProfileEmpty();
        return;
    }

    const bool bDeleted =
        UGameplayStatics::DeleteGameInSlot(SlotName, UserIndex);

    UpdateDeleteResult(bDeleted);
}

Async save needs a small state machine

The beginner-safe rule is: one save/write operation per slot at a time.

Use a small enum or Boolean:

SaveState = Idle / Saving / Failed

Save requested
-> Branch SaveState == Idle
-> SaveState = Saving
-> Async Save Game to Slot
-> Completed
-> SaveState = Idle or Failed

That is better than letting every button click create another async request and then guessing which one completed last.

Lookalikes - which one do I want?

Node Returns / changes Use when
Does Save Game Exist Boolean Menu/startup needs to know whether a slot is present.
Create Save Game Object New in-memory SaveGame object You need a default object before first save.
Save Game to Slot Boolean after a synchronous save attempt Simple projects where a short blocking save is acceptable.
Async Save Game to Slot Completed pin with Success UI should stay responsive while saving.
Load Game From Slot SaveGame object or None You need to read an existing slot.
Async Load Game From Slot Completed pin with loaded object/success Loading should not block the UI.
Delete Game in Slot Boolean delete result Player confirmed removing a slot.
GameInstance Runtime object that survives Open Level Data should survive map travel but not necessarily quitting.

Rule of thumb: Exist checks and delete manage the slot; save/load manage a SaveGame object; your graph still owns the data copy.

Going deeper