Skip to content

YeboID Error Handling

Consistent error responses across all endpoints.


Error Response Format

All errors follow this structure:

json
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable message",
    "details": { }
  }
}
FieldTypeDescription
codestringMachine-readable error code (UPPER_SNAKE_CASE)
messagestringHuman-readable description
detailsobjectAdditional context (optional)

Error Categories

4xx Client Errors

Errors caused by the client request.

5xx Server Errors

Errors caused by server issues.


Complete Error Code Reference

Authentication Errors (AUTH_*)

CodeHTTPMessageWhen
AUTH_INVALID_PHONE400Invalid phone number formatPhone doesn't match E.164
AUTH_INVALID_PIN400PIN must be 4-6 digitsPIN format wrong
AUTH_INVALID_OTP400Invalid verification codeWrong OTP entered
AUTH_OTP_EXPIRED400Verification code has expiredOTP past expiry
AUTH_INVALID_CREDENTIALS401Invalid phone or PINWrong login credentials
AUTH_INVALID_TOKEN401Invalid access tokenToken malformed/tampered
AUTH_TOKEN_EXPIRED401Access token has expiredToken past expiry
AUTH_INVALID_REFRESH_TOKEN401Invalid refresh tokenRefresh token invalid
AUTH_REFRESH_TOKEN_EXPIRED401Refresh token has expiredRefresh token past expiry
AUTH_TEMP_TOKEN_INVALID400Invalid or expired verificationTemp token from OTP verify invalid
AUTH_ACCOUNT_LOCKED403Account temporarily lockedToo many failed PIN attempts
AUTH_ACCOUNT_NOT_FOUND404Account not foundPhone not registered
AUTH_PHONE_EXISTS409Phone number already registeredSignup with existing phone
AUTH_OTP_RATE_LIMITED429Too many OTP requestsExceeded OTP send limit
AUTH_SIGNIN_RATE_LIMITED429Too many sign in attemptsExceeded signin attempts

User Errors (USER_*)

CodeHTTPMessageWhen
USER_NOT_FOUND404User not foundUser doesn't exist
USER_PROFILE_INVALID400Invalid profile dataProfile update validation failed
USER_DELETE_PIN_REQUIRED400PIN required to delete accountMissing PIN for deletion
USER_DELETE_CONFIRMATION400Confirmation text requiredMissing "DELETE MY ACCOUNT"

Handle Errors (HANDLE_*)

CodeHTTPMessageWhen
HANDLE_INVALID_FORMAT400Handle must be 3-30 lowercase letters, numbers, or underscoresBad format
HANDLE_INVALID_EDGES400Handle cannot start or end with underscorehandle or handle
HANDLE_TAKEN409This handle is already takenSomeone else has it
HANDLE_RESERVED409This handle is reservedIn reserved list
HANDLE_COOLDOWN429You can change your handle again on30-day cooldown
HANDLE_CHECK_RATE_LIMITED429Too many handle checksExceeded check limit

Session Errors (SESSION_*)

CodeHTTPMessageWhen
SESSION_NOT_FOUND404Session not foundInvalid session ID
SESSION_ALREADY_REVOKED400Session already revokedDouble revocation

KYC Errors (KYC_*)

CodeHTTPMessageWhen
KYC_ALREADY_VERIFIED400Account is already verifiedRe-initiating KYC
KYC_PENDING400Verification already in progressRe-initiating while pending
KYC_REJECTED403Verification was rejectedAccess after rejection

General Errors

CodeHTTPMessageWhen
INVALID_REQUEST400Invalid request bodyMalformed JSON
MISSING_FIELD400Missing required field:Required field absent
INVALID_FIELD400Invalid value for field:Field validation failed
UNAUTHORIZED401Authentication requiredNo token provided
FORBIDDEN403You don't have permissionInsufficient permissions
NOT_FOUND404Resource not foundGeneric 404
RATE_LIMITED429Too many requestsGeneric rate limit
INTERNAL_ERROR500Something went wrongServer error
SERVICE_UNAVAILABLE503Service temporarily unavailableMaintenance/overload

Error Details

Some errors include additional context in the details field:

Validation Errors

json
{
  "success": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "Validation failed",
    "details": {
      "fields": [
        {
          "field": "phone",
          "message": "Must be in E.164 format"
        },
        {
          "field": "pin",
          "message": "Must be 4-6 digits"
        }
      ]
    }
  }
}

Rate Limit Errors

json
{
  "success": false,
  "error": {
    "code": "AUTH_OTP_RATE_LIMITED",
    "message": "Too many OTP requests",
    "details": {
      "limit": 3,
      "window": "1 hour",
      "retry_after": 2400
    }
  }
}

Account Locked

json
{
  "success": false,
  "error": {
    "code": "AUTH_ACCOUNT_LOCKED",
    "message": "Account temporarily locked",
    "details": {
      "locked_until": "2026-03-18T21:00:00Z",
      "unlock_method": "wait or reset PIN via OTP"
    }
  }
}

Handle Cooldown

json
{
  "success": false,
  "error": {
    "code": "HANDLE_COOLDOWN",
    "message": "You can change your handle again on April 18, 2026",
    "details": {
      "next_change_available": "2026-04-18T20:00:00Z",
      "days_remaining": 30
    }
  }
}

HTTP Status Code Summary

StatusMeaningCommon Codes
200OKSuccess
201CreatedAccount created
400Bad RequestValidation errors
401UnauthorizedAuth required/failed
403ForbiddenLocked/no permission
404Not FoundResource doesn't exist
409ConflictAlready exists
429Too Many RequestsRate limited
500Server ErrorInternal error
503UnavailableMaintenance

Client Handling

JavaScript Example

javascript
async function signIn(phone, pin) {
  try {
    const res = await fetch('/auth/signin', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ phone, pin })
    });
    
    const data = await res.json();
    
    if (!data.success) {
      switch (data.error.code) {
        case 'AUTH_INVALID_CREDENTIALS':
          showError('Wrong phone or PIN');
          break;
        case 'AUTH_ACCOUNT_LOCKED':
          const until = data.error.details.locked_until;
          showError(`Account locked until ${formatDate(until)}`);
          break;
        case 'AUTH_ACCOUNT_NOT_FOUND':
          showError('No account with this phone. Sign up?');
          break;
        default:
          showError(data.error.message);
      }
      return null;
    }
    
    return data.data;
  } catch (e) {
    showError('Network error. Try again.');
    return null;
  }
}

React Hook Example

jsx
function useYeboIDError() {
  const handleError = (error) => {
    const messages = {
      'AUTH_INVALID_CREDENTIALS': 'Wrong phone or PIN',
      'AUTH_ACCOUNT_LOCKED': 'Account locked. Try again later.',
      'HANDLE_TAKEN': 'This handle is already taken',
      'RATE_LIMITED': 'Too many attempts. Slow down.',
    };
    
    return messages[error.code] || error.message;
  };
  
  return { handleError };
}

Logging & Monitoring

Error Logging (Server-side)

All errors are logged with:

  • Request ID
  • User ID (if authenticated)
  • IP address
  • Error code
  • Stack trace (5xx only)

Alerting

ConditionAlert
5xx rate > 1%PagerDuty
429 rate > 10%Slack
AUTH_ACCOUNT_LOCKED spikeSlack

Last updated: March 18, 2026

One chat. Everything done.