Skip to main content

Error Handling

Learn how to handle errors gracefully in Magical Auth.

Error Response Format

All errors follow a consistent format:

{
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"status": 400,
"request_id": "req_abc123",
"details": {
"fields": {
"phone_number": "Must be a valid E.164 phone number format"
}
}
}

Error Codes

Client Errors (4xx)

Error CodeStatusDescription
BAD_REQUEST400Invalid JSON in request body
VALIDATION_ERROR400Request validation failed (see details.fields)
MISSING_PARAMETERS400Required parameters missing
SESSION_NOT_FOUND404Session expired or not found
CARRIER_NOT_ELIGIBLE422Carrier doesn't support Magical Auth
UNSUPPORTED_PLATFORM422Browser/platform not supported for the selected strategy
INVALID_CREDENTIAL_FORMAT422Invalid credential structure
INVALID_VERIFICATION422Authentication response invalid
RATE_LIMIT_EXCEEDED429Too many requests

Server Errors (5xx)

Error CodeStatusDescription
SERVICE_UNAVAILABLE503Carrier service temporarily unavailable
INTERNAL_SERVER_ERROR500Unexpected server error

Desktop Flow Responses

For desktop (QR code) sessions, the /process endpoint (verify-phone-number or get-phone-number) blocks server-side while waiting for the mobile device to complete authentication. The following non-error responses require specific handling:

StatusMeaningBodySDK Action
200Mobile completed authenticationNormal verified responseDone — use the result
202 AcceptedTimeout — session still active{ "status": "waiting", "retry": true, "session_expires_in_seconds": N }Re-issue the same /process request
503 Service UnavailableRolling deploy — server shutting downRetry-After: 1 headerRetry after the Retry-After interval (typically 1s)

Handling the 202 retry loop:

async function desktopVerify(sessionKey, credential, session) {
while (true) {
const response = await fetch('/api/phone-auth/process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session, credential, use_case: 'VerifyPhoneNumber' }),
signal: AbortSignal.timeout(60_000), // 60s client timeout
});

if (response.status === 200) {
return await response.json(); // verified result
}

if (response.status === 202) {
const body = await response.json();
if (!body.retry) throw new Error('Session expired');
continue; // re-issue the same request
}

if (response.status === 503) {
const retryAfter = response.headers.get('Retry-After') || '1';
await new Promise(r => setTimeout(r, parseInt(retryAfter) * 1000));
continue;
}

throw new Error(`Unexpected status: ${response.status}`);
}
}
tip

The SDK handles 202/503 retry logic automatically. This pattern is only needed if you are calling the Glide API directly without the SDK.

Handling Errors

JavaScript (Web Client SDK)

import { ERROR_CODES } from '@glideidentity/glide-fe-sdk-web';

try {
const result = await client.authenticate({
use_case: USE_CASE.VERIFY_PHONE_NUMBER,
phone_number: '+14155551234'
});
} catch (error) {
switch (error.code) {
case ERROR_CODES.CARRIER_NOT_ELIGIBLE:
// Show SMS fallback
showSMSVerification();
break;
case ERROR_CODES.UNSUPPORTED_PLATFORM:
// Show browser requirement message
showBrowserRequirement();
break;
case ERROR_CODES.USER_CANCELLED:
// User closed the prompt
break;
default:
console.error('Error:', error.code, error.message);
}
}

Node.js (Backend SDK)

import { MagicalAuthError } from '@glideidentity/glide-be-node-magical-auth';

try {
const response = await client.prepare(request);
} catch (error) {
if (error instanceof MagicalAuthError) {
console.log('Code:', error.code);
console.log('Message:', error.message);
console.log('Status:', error.status);
console.log('Request ID:', error.requestId);
}
}

Go (Backend SDK)

response, err := glideClient.MagicalAuth.Prepare(ctx, &req)
if err != nil {
if glideErr, ok := err.(*glide.MagicalAuthError); ok {
log.Printf("Code: %s, Message: %s, Status: %d",
glideErr.Code, glideErr.Message, glideErr.Status)
}
}

Java (Backend SDK)

import com.glideidentity.exception.MagicalAuthError;

try {
PrepareResponse response = glideClient.magicalAuth.prepare(request);
} catch (MagicalAuthError e) {
log.info("Code: {}, Message: {}, Status: {}",
e.getCode(), e.getMessage(), e.getStatus());

if (e.isRetryable()) {
// Implement retry with backoff for 429, 503, 5xx errors
}
}

Phone Number Mismatch

When verifying a phone number, a mismatch is not an error. Instead, you'll receive a successful response with verified: false:

{
"phone_number": "+14155551234",
"verified": false
}

This allows you to handle mismatches gracefully in your UI.

Best Practices

  1. Always provide user-friendly messages - Don't expose raw error codes to users
  2. Implement fallbacks - Have SMS/email backup for unsupported carriers
  3. Log request IDs - Include request_id in your logs for debugging
  4. Handle rate limits - Implement exponential backoff for retries
  5. Check platform support - Show browser requirements before starting the flow