Skip to main content

Overview

Advanced iMessage Kit uses Axios for HTTP requests and Socket.IO for real-time events. Understanding how to handle errors from both layers is essential for building reliable iMessage applications.

Error Types

HTTP Errors (Axios)

API calls throw Axios errors with structured response data:
try {
  await sdk.messages.sendMessage({
    chatGuid: "invalid-guid",
    message: "test",
  });
} catch (error: unknown) {
  if (axios.isAxiosError(error)) {
    console.error("Status:", error.response?.status);
    console.error("Data:", error.response?.data);
    console.error("Message:", error.message);
  } else {
    console.error("Unexpected error:", error);
  }
}

Connection Errors

Socket.IO connection failures emit error events:
sdk.on("error", (error: Error) => {
  console.error("Connection error:", error.message);
});

sdk.on("connect_error", (error) => {
  console.error("Failed to connect:", error.message);
});
Source code reference: /home/daytona/workspace/source/client.ts:303-307, /home/daytona/workspace/source/client.ts:322-324

Message Send Errors

Failed message sends trigger dedicated events:
sdk.on("message-send-error", (data) => {
  console.error("Failed to send message:");
  console.error("GUID:", data.guid);
  console.error("Text:", data.text);
  console.error("Error:", data.error);
});
Source code reference: /home/daytona/workspace/source/types/events.ts:11

Common Error Scenarios

Chat Not Found

Occurs when sending to a non-existent chat:
try {
  await sdk.messages.sendMessage({
    chatGuid: "iMessage;-;+1234567890",
    message: "Hello!",
  });
} catch (error: unknown) {
  if (axios.isAxiosError(error) && error.response?.status === 500) {
    const errorMessage = error.response?.data?.message;
    
    if (errorMessage?.includes("does not exist")) {
      console.log("Chat doesn't exist - creating automatically");
      // SDK auto-creates chat when using 'any;-;' prefix
    }
  }
}
The SDK includes automatic chat creation when using any;-;+number format. If the chat doesn’t exist, the SDK will create it and send the message.
Source code reference: /home/daytona/workspace/source/modules/message.ts:12-40

Authentication Failure

sdk.on("error", (error: Error) => {
  if (error.message.includes("Authentication failed")) {
    console.error("Invalid API key or server misconfiguration");
    console.error("Check your credentials:");
    console.error("- API key is correct");
    console.error("- Server URL is accessible");
    console.error("- Server requires authentication");
  }
});
Source code reference: /home/daytona/workspace/source/client.ts:304-307

Network Timeout

import axios from "axios";

try {
  const message = await sdk.messages.sendMessage({
    chatGuid: "any;-;+1234567890",
    message: "Hello!",
  });
} catch (error: unknown) {
  if (axios.isAxiosError(error)) {
    if (error.code === "ECONNABORTED") {
      console.error("Request timeout - server may be slow or unreachable");
    } else if (error.code === "ECONNREFUSED") {
      console.error("Connection refused - is the server running?");
    }
  }
}

Invalid Message GUID

try {
  await sdk.messages.editMessage({
    messageGuid: "invalid-guid",
    editedMessage: "Updated text",
  });
} catch (error: unknown) {
  if (axios.isAxiosError(error) && error.response?.status === 400) {
    console.error("Invalid message GUID or message not found");
  }
}

Error Handling Patterns

Pattern 1: Basic Try-Catch

import { SDK } from "@photon-ai/advanced-imessage-kit";

const sdk = SDK();

sdk.on("ready", async () => {
  try {
    const message = await sdk.messages.sendMessage({
      chatGuid: "any;-;+1234567890",
      message: "Hello from MOBAI!",
    });
    
    console.log("Sent:", message.guid);
  } catch (error: unknown) {
    const message = error instanceof Error ? error.message : String(error);
    console.error("Failed to send message:", message);
  }
});

await sdk.connect();
Source code reference: /home/daytona/workspace/source/examples/message-send.ts:9-19

Pattern 2: Typed Error Handling

import axios from "axios";

function handleError(error: unknown, context: string) {
  if (axios.isAxiosError(error)) {
    const status = error.response?.status;
    const data = error.response?.data;
    
    console.error(`${context}:`);
    console.error(`- Status: ${status}`);
    console.error(`- Message: ${data?.message || error.message}`);
    
    if (status === 404) {
      console.error("- Resource not found");
    } else if (status === 401 || status === 403) {
      console.error("- Authentication required");
    } else if (status === 500) {
      console.error("- Server error");
    }
  } else if (error instanceof Error) {
    console.error(`${context}: ${error.message}`);
  } else {
    console.error(`${context}: ${String(error)}`);
  }
}

// Usage
try {
  await sdk.messages.sendMessage({
    chatGuid: "any;-;+1234567890",
    message: "Hello!",
  });
} catch (error) {
  handleError(error, "Failed to send message");
}
Source code reference: /home/daytona/workspace/source/examples/utils.ts:24-31

Pattern 3: Retry Logic

async function sendMessageWithRetry(
  sdk: AdvancedIMessageKit,
  chatGuid: string,
  message: string,
  maxRetries = 3
) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await sdk.messages.sendMessage({ chatGuid, message });
    } catch (error: unknown) {
      if (axios.isAxiosError(error)) {
        const status = error.response?.status;
        
        // Don't retry client errors (4xx)
        if (status && status >= 400 && status < 500) {
          throw error;
        }
      }
      
      if (attempt === maxRetries) {
        throw error;
      }
      
      console.log(`Retry ${attempt}/${maxRetries}...`);
      await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
    }
  }
}

// Usage
try {
  const message = await sendMessageWithRetry(
    sdk,
    "any;-;+1234567890",
    "Hello!"
  );
  console.log("Sent:", message.guid);
} catch (error) {
  console.error("Failed after retries:", error);
}

Pattern 4: Event-Based Error Handling

import { SDK } from "@photon-ai/advanced-imessage-kit";

const sdk = SDK({
  serverUrl: "http://localhost:1234",
  apiKey: process.env.API_KEY,
});

// Connection errors
sdk.on("error", (error: Error) => {
  console.error("SDK Error:", error.message);
  
  // Handle specific error types
  if (error.message.includes("Authentication failed")) {
    console.error("Check API key configuration");
    process.exit(1);
  }
});

sdk.on("connect_error", (error) => {
  console.error("Connection Error:", error.message);
});

// Message send failures
sdk.on("message-send-error", (data) => {
  console.error("Message Send Failed:");
  console.error("- Message:", data.text);
  console.error("- GUID:", data.guid);
  console.error("- Error:", data.error);
  
  // Implement retry logic or alert user
});

// Reconnection failures
sdk.socket.io.on("reconnect_failed", () => {
  console.error("Reconnection failed after all attempts");
  // Alert monitoring system or exit
});

await sdk.connect();

Best Practices

1. Always Use Type Guards

import axios from "axios";

try {
  await sdk.messages.sendMessage({
    chatGuid: "any;-;+1234567890",
    message: "Hello!",
  });
} catch (error: unknown) {
  // ✓ Good - check error type first
  if (axios.isAxiosError(error)) {
    console.error("Axios error:", error.response?.status);
  } else if (error instanceof Error) {
    console.error("Error:", error.message);
  } else {
    console.error("Unknown error:", error);
  }
  
  // ✗ Bad - assumes error is Error type
  // console.error((error as Error).message);
}

2. Check Response Status

import axios from "axios";

try {
  await sdk.messages.sendMessage({
    chatGuid: "iMessage;-;+1234567890",
    message: "Hello!",
  });
} catch (error: unknown) {
  if (axios.isAxiosError(error)) {
    const status = error.response?.status;
    
    switch (status) {
      case 400:
        console.error("Invalid request parameters");
        break;
      case 401:
        console.error("Unauthorized - check API key");
        break;
      case 404:
        console.error("Chat or resource not found");
        break;
      case 500:
        console.error("Server error");
        break;
      default:
        console.error("Unexpected error:", status);
    }
  }
}

3. Handle Both Sync and Async Errors

// Handle async errors with try-catch
sdk.on("ready", async () => {
  try {
    await sdk.messages.sendMessage({
      chatGuid: "any;-;+1234567890",
      message: "Hello!",
    });
  } catch (error) {
    console.error("Send failed:", error);
  }
});

// Handle sync errors with event listeners
sdk.on("error", (error: Error) => {
  console.error("Connection error:", error.message);
});

sdk.on("message-send-error", (data) => {
  console.error("Message send error:", data);
});

await sdk.connect();

4. Implement Graceful Degradation

async function sendMessage(chatGuid: string, message: string) {
  try {
    return await sdk.messages.sendMessage({ chatGuid, message });
  } catch (error: unknown) {
    if (axios.isAxiosError(error)) {
      const status = error.response?.status;
      
      // Chat doesn't exist - try with 'any' prefix
      if (status === 500 && chatGuid.startsWith("iMessage")) {
        const address = chatGuid.split(";")[2];
        console.log("Retrying with auto-detect...");
        
        return await sdk.messages.sendMessage({
          chatGuid: `any;-;${address}`,
          message,
        });
      }
    }
    
    throw error;
  }
}

5. Log Errors Appropriately

import { SDK } from "@photon-ai/advanced-imessage-kit";

const sdk = SDK({
  serverUrl: "http://localhost:1234",
  logLevel: "debug", // Use 'debug' for development, 'info' for production
});

sdk.on("error", (error: Error) => {
  // Production: log to monitoring service
  console.error("[ERROR]", {
    timestamp: new Date().toISOString(),
    message: error.message,
    stack: error.stack,
  });
});

try {
  await sdk.messages.sendMessage({
    chatGuid: "any;-;+1234567890",
    message: "Hello!",
  });
} catch (error: unknown) {
  // Development: detailed error info
  if (axios.isAxiosError(error)) {
    console.error("Request failed:", {
      status: error.response?.status,
      data: error.response?.data,
      config: error.config,
    });
  }
}

Error Recovery Strategies

Automatic Chat Creation

The SDK automatically creates chats when they don’t exist:
// This will auto-create the chat if needed
await sdk.messages.sendMessage({
  chatGuid: "any;-;+1234567890",
  message: "Hello!",
});
Source code reference: /home/daytona/workspace/source/modules/message.ts:20-38, /home/daytona/workspace/source/lib/auto-create-chat.ts

Connection Recovery

The SDK automatically reconnects on connection loss:
// SDK configuration (internal)
const socketConfig = {
  reconnection: true,
  reconnectionAttempts: Infinity, // Never give up
  reconnectionDelay: 100,         // Start with 100ms
  reconnectionDelayMax: 2000,     // Max 2 seconds
};

// Monitor reconnection
sdk.socket.io.on("reconnect", (attempt) => {
  console.log(`Reconnected after ${attempt} attempt(s)`);
});
Source code reference: /home/daytona/workspace/source/client.ts:121-129

Message Deduplication

The SDK prevents duplicate message processing:
// Clear processed messages to prevent memory leaks
sdk.clearProcessedMessages(1000); // Keep last 1000 messages

// Check processed message count
const count = sdk.getProcessedMessageCount();
console.log(`Tracking ${count} processed messages`);
Source code reference: /home/daytona/workspace/source/client.ts:366-376, /home/daytona/workspace/source/client.ts:379-383

Complete Error Handling Example

import axios from "axios";
import { SDK } from "@photon-ai/advanced-imessage-kit";
import type { AdvancedIMessageKit } from "@photon-ai/advanced-imessage-kit";

const sdk = SDK({
  serverUrl: process.env.SERVER_URL || "http://localhost:1234",
  apiKey: process.env.API_KEY,
  logLevel: "info",
});

// Connection error handling
sdk.on("error", (error: Error) => {
  console.error("[SDK ERROR]", error.message);
  
  if (error.message.includes("Authentication")) {
    console.error("Fix authentication and restart");
    process.exit(1);
  }
});

sdk.on("connect_error", (error) => {
  console.error("[CONNECTION ERROR]", error.message);
});

sdk.on("message-send-error", (data) => {
  console.error("[MESSAGE SEND ERROR]", {
    guid: data.guid,
    text: data.text,
    error: data.error,
  });
});

// Reconnection monitoring
sdk.socket.io.on("reconnect_error", (error) => {
  console.warn("[RECONNECT ERROR]", error.message);
});

sdk.socket.io.on("reconnect_failed", () => {
  console.error("[RECONNECT FAILED] All attempts exhausted");
});

// API error handling
async function safeSendMessage(
  chatGuid: string,
  message: string
): Promise<void> {
  try {
    const result = await sdk.messages.sendMessage({ chatGuid, message });
    console.log("✓ Sent:", result.guid);
  } catch (error: unknown) {
    if (axios.isAxiosError(error)) {
      const status = error.response?.status;
      const errorData = error.response?.data;
      
      console.error("✗ Failed to send message:");
      console.error(`  Status: ${status}`);
      console.error(`  Message: ${errorData?.message || error.message}`);
      
      switch (status) {
        case 400:
          console.error("  Reason: Invalid parameters");
          break;
        case 404:
          console.error("  Reason: Chat not found");
          break;
        case 500:
          console.error("  Reason: Server error");
          break;
      }
    } else if (error instanceof Error) {
      console.error("✗ Error:", error.message);
    } else {
      console.error("✗ Unknown error:", error);
    }
    
    throw error;
  }
}

// Ready event
sdk.on("ready", async () => {
  console.log("✓ SDK ready");
  
  await safeSendMessage("any;-;+1234567890", "Hello!");
});

// Graceful shutdown
process.on("SIGINT", async () => {
  console.log("\nShutting down...");
  await sdk.close();
  process.exit(0);
});

await sdk.connect();

Build docs developers (and LLMs) love