Skip to main content

Error Handling

The Moitribe SDK provides structured error handling with status codes and error messages to help you handle failures gracefully.

Error Response Structure​

All SDK callbacks receive responses with a consistent error structure:

interface ErrorResponse {
success: boolean; // Always false for errors
code: number; // Error status code
message: string; // Human-readable error message
[key: string]: any; // Additional error data
}

Basic Error Handling Pattern​

MoitribeSDK('my-game', 'getprofile', {}, (result) => {
if (result.success) {
// Handle success
console.log('Profile loaded:', result.data);
} else {
// Handle error
console.error('Error loading profile:', result.message);
console.error('Status code:', result.code);
}
});

Status Codes​

The SDK provides comprehensive status codes through the StatusCodes enum:

import { StatusCodes } from '@veniso/moitribe-js';

// Common status codes
console.log(StatusCodes.STATUS_OK); // 0
console.log(StatusCodes.STATUS_INTERNAL_ERROR); // 1
console.log(StatusCodes.STATUS_SIGNED_IN_PLAYER_REQUIRED); // -6

General Status Codes​

CodeConstantDescription
0STATUS_OKOperation successful
1STATUS_INTERNAL_ERRORInternal server error
2STATUS_INCORRECT_GAMEIDInvalid game ID
-3STATUS_API_OBSOLETEAPI version obsolete
-4STATUS_API_SERVICE_IS_DOWNService unavailable
-5STATUS_INVALID_API_VERSIONInvalid API version
-6STATUS_SIGNED_IN_PLAYER_REQUIREDAuthentication required
-7STATUS_SIGNED_DELETED_PLAYERPlayer account deleted

Profile Status Codes​

CodeConstantDescription
13001STATUS_PROFILE_EMAIL_PHONENO_EXISTSEmail/phone already exists
13002STATUS_PROFILE_INSUFFICIENT_DETAILSInsufficient profile details
13003STATUS_PROFILE_ACCOUNT_NOT_FOUNDAccount not found
13004STATUS_PROFILE_NO_DATA_FOR_UPDATENo data to update
13005STATUS_PROFILE_OLD_PASSWORD_MISMATCHOld password incorrect
13006STATUS_PROFILE_INVALID_CREDENTIALSInvalid credentials
13007STATUS_PROFILE_UNSUPPORTED_SOCIAL_PLATFORMUnsupported social platform
13008STATUS_PROFACTION_VERIFY_NONEVerification required
13009STATUS_INVALID_PLAYER_IDInvalid player ID
13010STATUS_INVALID_LOGIN_OPTIONInvalid login option
13011STATUS_PROFACTION_OTP_PARAM_INVALIDInvalid OTP parameters
13012STATUS_PROFACTION_OTP_INCORRECTIncorrect OTP
13013STATUS_PROFACTION_OTP_UNAVAILABLEOTP service unavailable
13014STATUS_PROFACTION_CALL_VERIFY_FIRSTVerification required first

Leaderboard Status Codes​

CodeConstantDescription
12001STATUS_LEADERBOARD_SUBMIT_SCORE_FAILEDScore submission failed
12002STATUS_LEADERBOARD_SCORE_ZEROScore cannot be zero

Real-Time Multiplayer Status Codes​

CodeConstantDescription
7002STATUS_INVALID_REAL_TIME_ROOM_IDInvalid room ID
7005STATUS_REAL_TIME_INACTIVE_ROOMRoom is inactive
7008STATUS_REAL_TIME_NO_SLOTNo available slots
7009STATUS_REAL_TIME_SIZE_ZERORoom size is zero
7010STATUS_REAL_TIME_PLAYER_ALREADY_IN_ROOMPlayer already in room

Tournament Status Codes​

CodeConstantDescription
15001STATUS_TOURNAMENT_NOT_FOUNDTournament not found
15002STATUS_TOURNAMENT_OUT_OF_DATETournament data outdated
15003STATUS_TOURNAMENT_PARTICIPANTS_FULLTournament full
15004STATUS_TOURNAMENT_VERIFIED_REQUIREDVerification required
15005STATUS_TOURNAMENT_NOT_JOINEDNot joined tournament
15006STATUS_TOURNAMENT_SEND_SUBTOURNAMENT_IDSub-tournament ID required
15007STATUS_TOURNAMENT_ALREADY_JOINEDAlready joined tournament
15008STATUS_TOURNAMENT_NO_ID_SENTNo tournament ID sent
15009STATUS_TOURNAMENT_NO_CLAIMSNo tournament claims

Advanced Error Handling​

Centralized Error Handler​

Create a centralized error handler for consistent error management:

import { StatusCodes } from '@veniso/moitribe-js';

interface SDKResult<T = any> {
success: boolean;
data?: T;
code?: number;
message?: string;
}

class ErrorHandler {
static handle<T>(result: SDKResult<T>, onSuccess?: (data: T) => void, onError?: (error: { code: number; message: string }) => void): void {
if (result.success && result.data) {
onSuccess?.(result.data);
} else {
const error = {
code: result.code || StatusCodes.STATUS_INTERNAL_ERROR,
message: result.message || 'Unknown error occurred'
};
onError?.(error);

// Log error for debugging
console.error('SDK Error:', error);
}
}

static isAuthenticationError(code: number): boolean {
return [
StatusCodes.STATUS_SIGNED_IN_PLAYER_REQUIRED,
StatusCodes.STATUS_SIGNED_DELETED_PLAYER,
StatusCodes.STATUS_PROFILE_INVALID_CREDENTIALS
].includes(code);
}

static isNetworkError(code: number): boolean {
return [
StatusCodes.STATUS_API_SERVICE_IS_DOWN,
StatusCodes.STATUS_API_OBSOLETE,
StatusCodes.STATUS_INVALID_API_VERSION
].includes(code);
}

static getErrorMessage(code: number): string {
const errorMessages: Record<number, string> = {
[StatusCodes.STATUS_SIGNED_IN_PLAYER_REQUIRED]: 'Player authentication required',
[StatusCodes.STATUS_PROFILE_INVALID_CREDENTIALS]: 'Invalid login credentials',
[StatusCodes.STATUS_LEADERBOARD_SUBMIT_SCORE_FAILED]: 'Failed to submit score',
[StatusCodes.STATUS_REAL_TIME_NO_SLOT]: 'No available slots in room',
[StatusCodes.STATUS_TOURNAMENT_FULL]: 'Tournament is full'
};

return errorMessages[code] || `Error code: ${code}`;
}
}

// Usage
MoitribeSDK('my-game', 'getprofile', {}, (result) => {
ErrorHandler.handle(
result,
(profile) => {
console.log('Profile loaded:', profile.name);
},
(error) => {
if (ErrorHandler.isAuthenticationError(error.code)) {
// Redirect to login
console.log('Authentication required, redirecting to login...');
} else {
console.error('Operation failed:', ErrorHandler.getErrorMessage(error.code));
}
}
);
});

Retry Logic​

Implement retry logic for transient errors:

class RetryHandler {
static async executeWithRetry<T>(
operation: () => Promise<SDKResult<T>>,
maxRetries: number = 3,
delay: number = 1000
): Promise<SDKResult<T>> {
let lastResult: SDKResult<T>;

for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
lastResult = await operation();

if (lastResult.success) {
return lastResult;
}

// Don't retry on authentication or validation errors
if (ErrorHandler.isAuthenticationError(lastResult.code || 0)) {
return lastResult;
}

if (attempt < maxRetries) {
console.log(`Attempt ${attempt} failed, retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // Exponential backoff
}
} catch (error) {
console.error(`Attempt ${attempt} threw error:`, error);
if (attempt === maxRetries) {
throw error;
}
}
}

return lastResult!;
}
}

// Usage with callback wrapper
const executeSDKWithRetry = <T>(
gameId: string,
method: string,
params: any,
callback: (result: SDKResult<T>) => void,
maxRetries: number = 3
) => {
const operation = () => new Promise<SDKResult<T>>((resolve) => {
MoitribeSDK(gameId, method, params, resolve);
});

RetryHandler.executeWithRetry(operation, maxRetries)
.then(callback)
.catch(error => {
callback({
success: false,
code: StatusCodes.STATUS_INTERNAL_ERROR,
message: error.message
});
});
};

Error Boundaries​

Create error boundaries for different operations:

class ProfileManager {
static loadProfile(gameId: string, callback: (profile?: SignedInProfile, error?: string) => void): void {
MoitribeSDK(gameId, 'getprofile', {}, (result) => {
if (result.success) {
callback(result.data);
} else {
let errorMessage = 'Failed to load profile';

switch (result.code) {
case StatusCodes.STATUS_SIGNED_IN_PLAYER_REQUIRED:
errorMessage = 'Please log in to view your profile';
break;
case StatusCodes.STATUS_PROFILE_ACCOUNT_NOT_FOUND:
errorMessage = 'Profile not found';
break;
case StatusCodes.STATUS_API_SERVICE_IS_DOWN:
errorMessage = 'Service temporarily unavailable';
break;
default:
errorMessage = result.message || errorMessage;
}

callback(undefined, errorMessage);
}
});
}
}

class LeaderboardManager {
static submitScore(
gameId: string,
leaderboardId: string,
score: number,
callback: (success: boolean, message?: string) => void
): void {
if (score <= 0) {
callback(false, 'Score must be greater than zero');
return;
}

MoitribeSDK(gameId, 'submitscore', {
leaderboardid: leaderboardId,
score: score
}, (result) => {
if (result.success) {
callback(true, 'Score submitted successfully');
} else {
let errorMessage = 'Failed to submit score';

switch (result.code) {
case StatusCodes.STATUS_LEADERBOARD_SCORE_ZERO:
errorMessage = 'Score cannot be zero';
break;
case StatusCodes.STATUS_LEADERBOARD_SUBMIT_SCORE_FAILED:
errorMessage = 'Score submission failed. Please try again.';
break;
default:
errorMessage = result.message || errorMessage;
}

callback(false, errorMessage);
}
});
}
}

Connection Error Handling​

Handle connection-related errors with connection callbacks:

const connectionCallbacks = {
onConnectionLost: (errorCode: number, errorMsg: string) => {
console.error('Connection lost:', errorCode, errorMsg);

// Show user-friendly message
if (errorCode === StatusCodes.STATUS_API_SERVICE_IS_DOWN) {
alert('Service is temporarily unavailable. Please try again later.');
} else {
alert('Connection lost. Please check your internet connection.');
}
},

onConnected: (isReconnect: boolean, URI: string) => {
console.log('Connected to:', URI);
if (isReconnect) {
console.log('Reconnected successfully');
// Refresh data after reconnection
refreshGameData();
}
},

onSuccessConnect: () => {
console.log('Connection established');
},

onFailureConnect: () => {
console.error('Failed to establish connection');
alert('Failed to connect to game servers. Please try again.');
}
};

// Initialize with connection callbacks
MoitribeSDK('my-game', 'init', {
connectionCallbacks: connectionCallbacks
}, (result) => {
console.log('SDK initialized:', result.success);
});

Best Practices​

1. Always Check Success Flag​

// ✓ Good
MoitribeSDK('my-game', 'getprofile', {}, (result) => {
if (result.success) {
// Process success
} else {
// Handle error
}
});

// ✗ Bad
MoitribeSDK('my-game', 'getprofile', {}, (result) => {
// Process result without checking success
});

2. Provide User-Friendly Messages​

const getUserFriendlyMessage = (code: number, technicalMessage: string): string => {
const userMessages: Record<number, string> = {
[StatusCodes.STATUS_SIGNED_IN_PLAYER_REQUIRED]: 'Please log in to continue',
[StatusCodes.STATUS_API_SERVICE_IS_DOWN]: 'Service temporarily unavailable',
[StatusCodes.STATUS_LEADERBOARD_SUBMIT_SCORE_FAILED]: 'Failed to save score. Please try again.'
};

return userMessages[code] || 'An error occurred. Please try again.';
};

3. Log Technical Details​

MoitribeSDK('my-game', 'submitscore', { leaderboardid: 'scores', score: 1000 }, (result) => {
if (!result.success) {
// Log technical details for debugging
console.error('Score submission failed:', {
code: result.code,
message: result.message,
timestamp: new Date().toISOString(),
leaderboardId: 'scores',
score: 1000
});

// Show user-friendly message
alert(getUserFriendlyMessage(result.code, result.message));
}
});

Next Steps​

warning

Never expose technical error messages directly to users. Always provide user-friendly messages while logging technical details for debugging.