Quick answer: Achievement unlock failures are almost always caused by one of three things: the platform SDK wasn’t initialized before the unlock call, the game was offline and the unlock wasn’t queued for later, or the achievement ID in code doesn’t match the ID registered on the platform. Add structured logging to every unlock call, test in each platform’s test environment (not the editor), and verify every achievement is reachable in a normal playthrough before submitting for certification.
Few things frustrate players more than earning an achievement and not getting credit. They beat the boss, the health bar hits zero, the victory cutscene plays — and no popup. No trophy. No notification. The achievement page shows it locked. They post on your Steam forum, and now you have a bug report that says “achievements broken” with no additional context. Here’s how to prevent that, and how to debug it when it happens anyway.
SDK Initialization Order
The most common cause of achievement failures is calling the unlock API before the platform SDK is ready. On Steam, SteamAPI_Init() must return true before any Steamworks calls. On PlayStation, the trophy service requires the user to be signed in and the trophy pack to be registered. On Xbox, the achievement service is part of Xbox Live, which requires an authenticated user session.
The fix is defensive initialization. Check the SDK’s ready state before every achievement call, not just at startup. SDKs can lose their connection mid-session — the user signs out, the network drops, the platform overlay interrupts. If the SDK is not ready when you try to unlock, queue the unlock and retry on the next frame.
// AchievementManager.cs — defensive unlock pattern
using System.Collections.Generic;
using Steamworks;
public class AchievementManager
{
private Queue<string> pendingUnlocks = new();
public void Unlock(string achievementId)
{
if (!SteamManager.Initialized)
{
Debug.LogWarning(
$"Steam not ready, queueing: {achievementId}");
pendingUnlocks.Enqueue(achievementId);
return;
}
bool success = SteamUserStats.SetAchievement(achievementId);
if (success)
{
SteamUserStats.StoreStats();
Debug.Log($"Achievement unlocked: {achievementId}");
}
else
{
Debug.LogError(
$"SetAchievement failed: {achievementId}");
pendingUnlocks.Enqueue(achievementId);
}
}
public void FlushPending()
{
while (pendingUnlocks.Count > 0
&& SteamManager.Initialized)
{
Unlock(pendingUnlocks.Dequeue());
}
}
}
Call FlushPending() on every scene load and after any network reconnection event. This ensures queued unlocks are retried automatically without requiring the player to re-earn them.
Logging Every Unlock Attempt
When a player reports a missing achievement, you need to know exactly what happened. Did the game call the unlock API? Did the API return success or failure? Was the SDK initialized? Was the player online? Without logs, you are guessing.
Add structured logging to every achievement-related call. Log the achievement ID, the player’s progress value (for progressive achievements), the API return value, the SDK initialization state, and the network state. Include these logs in your bug report metadata so they are available in Bugnet alongside the player’s other diagnostic data.
For progressive achievements (e.g., “Kill 100 enemies”), also log the current progress value each time it increments. A common bug is the progress counter resetting on scene reload because it is stored in a local variable instead of the save file. The logs will show progress climbing to 97, then jumping back to 0.
Platform-Specific Test Modes
Each platform has its own achievement testing workflow, and none of them match your editor.
Steam: Use SteamUserStats.ClearAchievement() and StoreStats() to reset achievements between test runs. You can also use the steam_appid.txt file and Spacewar test app during development, but always verify in a real build with your actual App ID before shipping.
PlayStation: Use the debug trophy reset tool on your devkit. Trophies on PlayStation are particularly strict — the trophy pack must be registered with the platform, the icon must meet exact resolution requirements (480x270 for each trophy), and the unlock call must include the correct trophy ID from the registered pack. A mismatch between your code’s ID and the registered ID silently fails.
Xbox: Test in a sandbox environment with test accounts. Xbox achievements use Events and Stats — you fire an event, and the platform determines whether the achievement criteria are met. This indirection means your unlock logic is split between your game code and the Xbox backend configuration. Bugs can hide in either layer.
Common Certification Failures
Platform certification will reject your game if any achievement is unreachable. This means every achievement must be unlockable through normal gameplay without exploits, debug commands, or unreleased content. Before submitting for cert, play through the game and unlock every achievement. Document the path for each one.
“Certification testers will try to unlock every achievement in your game. If one is bugged, gated behind unreleased DLC, or requires a sequence that’s impossible due to a logic error, the entire submission fails. Test every achievement manually before cert.”
Other common cert failures: achievement descriptions that say “Complete Chapter 5” but the achievement actually triggers at the start of Chapter 6 (timing mismatch), icons that are the wrong size or have transparency when the platform requires opaque backgrounds, and achievements that unlock retroactively on save load without re-checking the criteria (some platforms require the criteria to be met during the current session).
Offline Queueing
Steam handles offline achievement queuing natively — if the player is offline when SetAchievement is called, Steam syncs it on the next connection. PlayStation and Xbox require you to manage this yourself. Store pending unlocks in your save data (not just in memory) so they survive a game restart. On the next session start, check for pending unlocks and attempt to flush them.
Test this explicitly: disconnect from the network, earn an achievement, quit the game, reconnect, relaunch, and verify the achievement unlocks. This is the exact flow a player on a laptop or console in rest mode will hit, and it is rarely tested during development.
Related Issues
If achievements are not transferring across platforms with cross-save, see How to Test Cross-Save Between Platforms. For tracking achievement bugs alongside other game health metrics, check How to Set Up a Game Health Scorecard.
If a player earned it, they deserve the trophy. Queue it, retry it, and log everything.