All errors follow a consistent JSON format:
{
"error": "Error message describing what went wrong",
"status": "failed",
"query": "original search query",
"search_type": "web",
"analysis_mode": "basic",
"from_date": null,
"to_date": null,
"timestamp": "2025-06-04T10:30:00.000Z",
"request_id": "req_1717498200000_abc123xyz"
}
Error Categories
API Key Errors
Missing API Key
Cause: XAI_API_KEY environment variable not set
Error:
{
"error": "API service is not healthy - missing XAI_API_KEY",
"status": "failed"
}
Implementation:
if (!this.apiKey) {
this.isHealthy = false;
Logger.error("XAI_API_KEY environment variable is required");
}
Resolution:
- Add
XAI_API_KEY to Claude Desktop configuration
- Verify the API key format (starts with
xai-)
- Restart Claude Desktop
- Run
health_check to verify
Validation Errors
Empty Query
Error:
{
"error": "Search query must be a non-empty string"
}
Validation:
if (!query || typeof query !== 'string') {
throw new Error("Search query must be a non-empty string");
}
Query Too Long
Error:
{
"error": "Search query too long (max 1000 characters)"
}
Validation:
if (sanitizedQuery.length > 1000) {
throw new Error("Search query too long (max 1000 characters)");
}
Error:
{
"error": "from_date must be in ISO8601 format (YYYY-MM-DD)"
}
Validation:
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
if (!dateRegex.test(dateString)) {
throw new Error(`${paramName} must be in ISO8601 format (YYYY-MM-DD)`);
}
Invalid Date Range
Error:
{
"error": "from_date must be before or equal to to_date"
}
Validation:
const fromDateObj = new Date(validatedFromDate);
const toDateObj = new Date(validatedToDate);
if (fromDateObj > toDateObj) {
throw new Error("from_date must be before or equal to to_date");
}
API Request Errors
Rate Limiting (429)
Error:
{
"error": "API request failed: 429 - Rate limit exceeded"
}
Automatic Retry: Yes (with exponential backoff)
Retry Logic:
if ((response.status >= 500 || response.status === 429) && retryCount < this.maxRetries) {
const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
Logger.warn(`Request failed, retrying in ${backoffDelay}ms`, {
status: response.status,
attempt: retryCount + 1,
maxRetries: this.maxRetries
});
await new Promise(resolve => setTimeout(resolve, backoffDelay));
return this.makeRequest(endpoint, data, retryCount + 1);
}
Backoff Schedule:
- Attempt 1: Wait 1 second (2^0 * 1000ms)
- Attempt 2: Wait 2 seconds (2^1 * 1000ms)
- Attempt 3: Wait 4 seconds (2^2 * 1000ms)
- Attempt 4: Wait 8 seconds (2^3 * 1000ms)
- Maximum: 10 seconds cap
The server automatically handles rate limiting. You don’t need to implement retry logic in your application.
Server Errors (5xx)
Error:
{
"error": "API request failed: 500 - Internal Server Error"
}
Automatic Retry: Yes (same logic as rate limiting)
Max Retries: Configured by GROK_MAX_RETRIES (default: 3)
Timeout Errors
Error:
{
"error": "Request timeout after 30000ms"
}
Implementation:
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.requestTimeout);
if (error.name === 'AbortError') {
const timeoutError = new Error(`Request timeout after ${this.requestTimeout}ms`);
this.lastError = timeoutError.message;
throw timeoutError;
}
Resolution:
- Increase
GROK_TIMEOUT in configuration
- Use basic mode instead of comprehensive
- Reduce
max_results parameter
- Check network connectivity
Comprehensive analyses typically take 20-40 seconds. Set GROK_TIMEOUT to 45000-60000ms for comprehensive mode.
Network Errors
Error:
{
"error": "Failed to make API request: Network connection failed"
}
Automatic Retry: Yes (for non-API errors)
Retry Logic:
if (retryCount < this.maxRetries && !error.message.includes('API request failed:')) {
const backoffDelay = Math.min(1000 * Math.pow(2, retryCount), 10000);
Logger.warn(`Network error, retrying in ${backoffDelay}ms`, {
error: error.message,
attempt: retryCount + 1
});
await new Promise(resolve => setTimeout(resolve, backoffDelay));
return this.makeRequest(endpoint, data, retryCount + 1);
}
Parsing Errors
JSON Parsing Failed
Error:
{
"error": "Failed to parse search results: Unexpected token in JSON"
}
Fallback Behavior: Returns fallback response with raw content
Fallback Response:
createFallbackResponse(query, content, citations, citationMetadata, analysisMode) {
const fallbackResults = [{
title: `Search results for: ${query}`,
snippet: content.substring(0, 500) + (content.length > 500 ? "..." : ""),
url: citations[0] || null,
source: "grok-live-search",
published_date: new Date().toISOString().split('T')[0]
}];
// ...
}
The server uses multiple JSON parsing strategies to handle different response formats. Parsing rarely fails completely.
Retry Mechanism
Automatic Retry Conditions
The server automatically retries requests for:
- Server Errors: HTTP 5xx status codes
- Rate Limiting: HTTP 429 status code
- Network Errors: Connection failures, DNS errors, etc.
Non-Retry Conditions
The server does NOT retry for:
- Validation Errors: Input validation failures
- Client Errors: HTTP 4xx (except 429)
- API Key Errors: Missing or invalid API key
- Final Retry Exhaustion: After max retries exceeded
Retry Configuration
async makeRequest(endpoint, data, retryCount = 0) {
// Retry logic with exponential backoff
}
Default Configuration:
- Max Retries: 3 (configurable via
GROK_MAX_RETRIES)
- Initial Delay: 1 second
- Backoff: Exponential (2^n)
- Max Delay: 10 seconds
Custom Configuration:
{
"env": {
"XAI_API_KEY": "your-key",
"GROK_MAX_RETRIES": "5"
}
}
Error Logging
The server logs all errors using structured logging:
class Logger {
static log(level, message, data = null) {
const timestamp = new Date().toISOString();
const logEntry = {
timestamp,
level,
message,
...(data && { data })
};
if (level === 'error') {
console.error(JSON.stringify(logEntry));
}
}
}
Log Levels:
error: Critical errors, failed requests
warn: Retry attempts, recoverable issues
info: General information
debug: Detailed debugging information
Example Log Entry:
{
"timestamp": "2025-06-04T10:30:00.000Z",
"level": "error",
"message": "Search failed",
"data": {
"query": "test query",
"error": "API request failed: 429"
}
}
Health Monitoring
Use the health_check tool to monitor server health:
{
"tool": "health_check",
"parameters": {}
}
Healthy Response:
{
"server_healthy": true,
"api_healthy": true,
"uptime_ms": 3600000,
"total_requests": 150,
"error_count": 5,
"success_rate": "96.67%",
"api_details": {
"hasApiKey": true,
"cacheSize": 12,
"lastError": null
}
}
Unhealthy Response:
{
"server_healthy": true,
"api_healthy": false,
"api_details": {
"hasApiKey": false,
"cacheSize": 0,
"lastError": "API service is not healthy - missing XAI_API_KEY"
}
}
Troubleshooting Guide
Common Issues and Solutions
Issue: “API service is not healthy”
Diagnosis:
{
"tool": "health_check"
}
Solution:
- Check
api_details.hasApiKey in health response
- Verify
XAI_API_KEY in Claude Desktop config
- Ensure API key starts with
xai-
- Restart Claude Desktop
Issue: Frequent Timeouts
Diagnosis:
- Check
health_check for lastError containing “timeout”
- Review request patterns (comprehensive vs basic)
Solution:
{
"env": {
"GROK_TIMEOUT": "60000", // Increase to 60 seconds
"GROK_MAX_RETRIES": "5" // Increase retries
}
}
Issue: High Error Rate
Diagnosis:
{
"success_rate": "75.00%", // Below 90%
"error_count": 25
}
Possible Causes:
- Network connectivity issues
- API rate limiting
- Invalid queries or parameters
- Timeout too low for comprehensive mode
Solution:
- Review error logs for patterns
- Adjust timeout and retry settings
- Validate input parameters
- Check xAI API status
Issue: “Rate limit exceeded”
Automatic Handling: Server retries automatically
Manual Solution:
- Wait for retry to complete (up to 10 seconds)
- Reduce request frequency
- Increase
GROK_MAX_RETRIES for more attempts
- Check xAI API limits and usage
Issue: No Results Returned
Diagnosis:
- Check if response has empty
results array
- Review query and date parameters
- Verify search type is appropriate
Solution:
- Try different search type (web vs news)
- Remove or adjust date filters
- Simplify query terms
- Increase
max_results parameter
Debugging Steps
- Check Health Status:
- Review Error Response:
- Check
error field for details
- Note
request_id for tracking
- Review
timestamp for timing issues
- Test with Simple Query:
{
"tool": "grok_search",
"parameters": {
"query": "test",
"analysis_mode": "basic",
"max_results": 3
}
}
- Check Configuration:
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json
- Verify Network:
Error Handling Best Practices
Validate inputs before sending requests:
function validateSearchParams(params) {
// Check query
if (!params.query || params.query.trim().length === 0) {
return { valid: false, error: "Query is required" };
}
if (params.query.length > 1000) {
return { valid: false, error: "Query too long" };
}
// Check dates
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
if (params.from_date && !dateRegex.test(params.from_date)) {
return { valid: false, error: "Invalid from_date format" };
}
return { valid: true };
}
Graceful Degradation
Handle errors gracefully:
function handleSearchResponse(response) {
if (response.error) {
// Log error
console.error(`Search failed: ${response.error}`);
// Provide fallback
return {
success: false,
message: "Search unavailable, please try again",
error: response.error
};
}
return {
success: true,
data: response.results
};
}
Retry Strategy
The server handles retries automatically. Do not implement additional retry logic in your application to avoid cascading delays.
Timeout Configuration
Set appropriate timeouts based on usage:
Basic Mode:
{"GROK_TIMEOUT": "30000"} // 30 seconds
Comprehensive Mode:
{"GROK_TIMEOUT": "60000"} // 60 seconds
Mixed Usage:
{"GROK_TIMEOUT": "45000"} // 45 seconds (compromise)
Server Error Tracking
The server tracks errors internally:
this.lastError = error.message;
Access via health check:
{
"api_details": {
"lastError": "Request timeout after 30000ms"
}
}
lastError shows the most recent error. Use this to diagnose recurring issues.
Request Tracking
Every error response includes a unique request ID:
request_id: `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
Format: req_{timestamp}_{random}
Example: req_1717498200000_abc123xyz
Use this to track specific failed requests in logs.