Skip to content

Error Tracking

Capture errors and crashes in your game with automatic stack traces. The SDK also includes a Flight Recorder that captures 60 seconds of telemetry data before each error, helping you understand what led to the crash.

Automatic Error Capture (since SDK v1.4.0)

Section titled “Automatic Error Capture (since SDK v1.4.0)”

The SDK hooks into Godot’s logging system via OS.add_logger() and forwards every runtime error to the dashboard automatically — no track_error() call needed in your game code. This catches engine-level errors that GDScript can’t catch with try/except patterns: null dereferences, missing methods, signal mismatches, shader errors, etc.

Requirements:

  • Godot 4.5 or newer (Logger class must be exposed to GDScript)
  • The Project Setting quest_data/auto_capture_errors must be true (default)

What gets captured:

  • All ERROR_TYPE_ERROR, ERROR_TYPE_SCRIPT, and ERROR_TYPE_SHADER events
  • Function name, source file, line number, error code, rationale message
  • Full multi-language script backtrace (Array[ScriptBacktrace] — GDScript + C# frames if Mono build)
  • OS, game version, dedup hash for crash-grouping

What is intentionally NOT captured:

  • WARNING: and SCRIPT WARNING: (too noisy, rarely actionable)
  • Errors originating from inside the SDK itself (addons/quest_data/...) — feedback-loop guard

Dedup behavior: the same file:line:function signature fires at most once per 30 seconds. If your hover handler crashes 60 times per second, the dashboard sees one event per 30s window — no spam.

If you don’t want auto-capture (e.g. you want to manually decide what to ship to the backend):

# project.godot
[quest_data]
auto_capture_errors=false

Or via Project Settings UI: Project > Project Settings > Quest Data > Auto Capture Errors. You can still call QuestData.track_error() manually for caught exceptions even with auto-capture off.

QuestData.track_error(error_name: String, error_msg: String = "")
ParameterTypeDefaultDescription
error_nameStringrequiredError type identifier (e.g. "NullReference", "SaveCorrupted")
error_msgString""Human-readable error message

Sends an error_occurred event with:

  • Full GDScript stack trace
  • Stack snippet (short version for quick scanning)
  • Operating system info
  • Game version (from application/config/version in ProjectSettings)
  • Flight Recorder data (last 60 seconds of FPS, memory, events)
# Track a caught error
func load_save_file(path: String) -> Dictionary:
var file = FileAccess.open(path, FileAccess.READ)
if file == null:
QuestData.track_error("SaveLoadFailed", "Could not open: " + path)
return {}
var data = file.get_var()
if not data is Dictionary:
QuestData.track_error("SaveCorrupted", "Expected Dictionary, got " + type_string(typeof(data)))
return {}
return data
# Track unexpected states
func apply_damage(amount: int):
if amount < 0:
QuestData.track_error("InvalidDamage", "Negative damage: " + str(amount))
return
health -= amount
func parse_server_response(json_string: String) -> Dictionary:
var json = JSON.new()
var error = json.parse(json_string)
if error != OK:
QuestData.track_error("JSONParseError", json.get_error_message())
return {}
return json.get_data()

The SDK continuously captures telemetry snapshots every second, keeping the last 60 seconds in a circular buffer. When track_error() is called, this data is attached to the error event.

Each snapshot includes:

  • FPS at that moment
  • Memory usage (MB)
  • Active scene name
  • Recent events tracked in that second

This lets you see what happened before the crash — was the game running low on memory? Did FPS drop? What events fired right before?

In the dashboard under Analytics > Dashboard, the error detail view shows:

  • Error grouping — Same errors are grouped by error_name
  • Occurrence count — How often this error happens
  • Stack trace — Full and snippet views
  • Flight Recorder charts — FPS and memory graphs for the 60 seconds before the crash
  1. track_error() captures the current GDScript call stack via get_stack()
  2. The stack is formatted into a readable string and a short snippet
  3. Flight Recorder data (last 60 snapshots) is serialized and attached
  4. The event is queued like any other event (batched, offline-safe)
  1. Use descriptive error names"SaveCorrupted" is better than "Error"
  2. Include context in the message — File paths, expected vs. actual values, player state
  3. Don’t track expected failures — A player losing a level is not an error
  4. Track at boundaries — File I/O, network responses, JSON parsing, scene transitions
  5. Keep error names consistent — Same error type should always use the same error_name for grouping