Robust Error Handling for saving game data

Godot Version

4.5

Question

Dear Godot Veterans,

I am looking at FileAccess — Godot Engine (stable) documentation in English

I would like to make my code robust in error handling when any error has occurred during saving a file. I see there are get_open_error() and get_error() in there, so I believe this should be just this, right?

For obtaining errors during opening a file:

var file:FileAccess = FileAccess.open( path, FileAccess.WRITE)
if file == null:
	var err:Error = FileAccess.get_open_error()
	print( "Error Code " + str(err) )
	...
	...

For obtaining errors during store_line or any other FileAccess operation:

var store_result:bool = file.store_line( ... )
if store_result:
	print( "saved successfully" )
	file.close()
else:
	var err:Error = file.get_error()
	print( "Error Code " + str(err) )
	file.close()

Questions:

  1. I believe file.close() should be performed after file.get_error(). Correct?
  2. For file.close() , could there be a possible chance that it could create an error? From FileAccess — Godot Engine (stable) documentation in English :

void close()

Closes the currently opened file and prevents subsequent read/write operations. Use flush() to persist the data to disk without closing the file.

Note: FileAccess will automatically close when it’s freed, which happens when it goes out of scope or when it gets assigned with null. In C# the reference must be disposed after we are done using it, this can be done with the using statement or calling the Dispose method directly.

and also:

void flush()

Writes the file’s buffer to disk. Flushing is automatically performed when the file is closed. This means you don’t need to call flush() manually before closing a file. Still, calling flush() can be used to ensure the data is safe even if the project crashes instead of being closed gracefully.

Note: Only call flush() when you actually need it. Otherwise, it will decrease performance due to constant disk writes.

This means those store_ functions store data in buffers first before they are written to the file, yes? This means there is one possible error. If the disk is full upon closing the file, the game will fail to save the file, yes? Will we get something like Error 13 ERR_FILE_CANT_WRITE here after file.close()? What would be the robust way to deal with this to prevent data loss?

  1. For disk almost full, I see we can just warn the player of their remaining disk space if it is too low before they start playing with DirAccess — Godot Engine (stable) documentation in English
var free_bytes:int = DirAccess.get_space_left() 

From the document, Returns the available space on the current directory's disk, in bytes. - current directory’s disk? How can I point to user:// in this case? I just need to point to the disk where Godot will save, I believe?

You can open the "user://" directory by that path

var user := DirAccess.open("user://")
var space := user.get_space_left()

I think you are pointing out a lot of valid flaws of Godot’s file writing. Buffered reading/writing is very important for speed but it does mean any error from store_line could be “promoted” to an allocation error which is pretty unrecoverable (and exceedingly rare) in modern operating systems. The buffers also mean flush should return a possible error (and thus close too, only because of the write-before-close). Another twist is that operating systems have their own buffer before actually writing to disk, but I think they will acknowledge and error no space left if the buffer and the disk remaining don’t match up before syncing.

Sadly I believe it’s common practice to assume you are good to go after the file opens successfully. Even Silent Hill 2 remake did not report errors saving when I had some access/ownership issue, the game ignored all errors and pretended to save.

Checking for space before writing should put you ahead of no space left errors. I can’t imagine much else error wise to watch out for during flush/storing, unless your "user://" directory is a network drive that gets disconnected, but what can you do if that happens right?

1 Like

@gertkeno Thank you for DirAccess.open and indeed, these are some scenarios that rare errors could occur.

But you know what? I think we might just need the code for saved data verification. After any writing to file and upon closing it, just reload the file back and validate for its content. The code for verification will depend on how you save your game and the structure of your saved data file(s).

This way, if any error, silent or not, has occurred, or any discrepancy is found, the player could be notified that their game is not saved properly.

1 Like