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.