Error handling
Every error code, when it fires, and how to recover.
Every failure mode in the SDK surfaces as a GameeError — either thrown
synchronously (validation, missing capability, calling init() twice) or as
a Promise rejection (everything that touches the wire).
import { GameeError } from '@gamee/sdk';
try {
await gamee.purchaseItemWithGems({ gemsCost: 50, itemName: 'extra_life' });
} catch (err) {
if (err instanceof GameeError) {
console.warn(err.code, err.method, err.message, err.cause);
} else {
throw err; // not ours — rethrow
}
}
The GameeError shape#
| Property | Type | Required | Notes |
|---|---|---|---|
name | 'GameeError' | true | Standard Error subclass. |
code | GameeErrorCode | true | The branchable identifier (see table below). |
method | string | false | Which SDK method produced the error, if applicable. |
message | string | true | Human-readable. Don’t parse — branch on code. |
cause | unknown | true | The underlying error if there was one. |
GameeErrorCode is exported as a TypeScript union for exhaustive switch:
import type { GameeErrorCode } from '@gamee/sdk';
function explain(code: GameeErrorCode): string {
switch (code) {
case 'VALIDATION':
return 'Bad input.';
case 'CAPABILITY_MISSING':
return 'Declare the capability in init().';
case 'BRIDGE_TIMEOUT':
return 'Platform did not respond.';
case 'BRIDGE_ERROR':
return 'Platform returned an error.';
case 'BRIDGE_OVERFLOW':
return 'Too many in-flight requests.';
case 'INVALID_STATE':
return 'Wrong time to call this.';
case 'NOT_SUPPORTED':
return 'Method not available on this platform.';
}
}
Codes#
VALIDATION#
Inputs failed the SDK’s local validation before anything reached the platform.
Triggered by:
- Unknown capability in
init({ capabilities }). logEventwith empty/oversizedname(max 24) orvalue(max 160).updateMissionProgressoutside[0, 100]or non-finite.updateScorewith non-finite score, negativeplayTime, or empty checksum.purchaseItemWithGemsmissingitemName/gemsCostor with negativegemsCost.
Recovery: fix the call site; this is a programmer error.
CAPABILITY_MISSING#
You called a gated method without declaring the matching capability.
const sdk = createSdk();
await sdk.init({ capabilities: [] }); // no 'saveState'
sdk.gameSaveState({}); // throws CAPABILITY_MISSING
Recovery: add the capability to your init() call. See
capabilities for which methods need which capability.
BRIDGE_TIMEOUT#
The platform did not respond within requestTimeoutMs (default 30 000 ms).
Only data-returning methods can hit this — fire-and-forget signals don’t track
responses.
Recovery: retry once on user action, then surface a soft error to the player. If you see this in production from a real platform, file a bug — the platform is supposed to respond.
async function safeShowAd(): Promise<boolean> {
try {
return (await gamee.showRewardedVideo()).videoPlayed;
} catch (err) {
if (err instanceof GameeError && err.code === 'BRIDGE_TIMEOUT') return false;
throw err;
}
}
BRIDGE_ERROR#
The platform returned an explicit error response. The platform’s error code/message
are forwarded into the GameeError’s message (and cause when available).
Recovery: depends on the method. Treat purchase/ad failures as “the action didn’t happen” and re-prompt the user.
BRIDGE_OVERFLOW#
You have more than maxPendingRequests data-returning calls in flight (default
256). The oldest pending request is rejected with this code so the new one
has a slot.
Recovery: don’t fan out hundreds of purchaseItemWithGems /
loadRewardedVideo calls. If you legitimately need a higher cap, raise
maxPendingRequests in SdkOptions.
INVALID_STATE#
Method called at the wrong time. The two cases that matter:
init()called twice. UsecreateSdk()for a fresh instance instead.- Anything called after
dispose(). All in-flight Promises reject with this code.
NOT_SUPPORTED#
Reserved for future use — a method exists in the API but the platform you’re
running on can’t honor it. The current SDK does not throw this code from any
of its public methods, but check for it in long-lived switches so adding new
methods later is a non-breaking change.
Top-level safety net#
For long-lived games it’s reasonable to set a top-level handler that logs unexpected errors to your analytics:
window.addEventListener('unhandledrejection', (e) => {
if (e.reason instanceof GameeError) {
track('gamee_error', { code: e.reason.code, method: e.reason.method });
}
});
If you have logEvents declared, you can ship a summary to the platform too:
window.addEventListener('unhandledrejection', (e) => {
if (e.reason instanceof GameeError) {
gamee.logEvent('gamee_err', `${e.reason.code}:${e.reason.method ?? ''}`);
}
});