firewalla-mcp-server
Version:
Model Context Protocol (MCP) server for Firewalla MSP API - Provides real-time network monitoring, security analysis, and firewall management through 28 specialized tools compatible with any MCP client
1,643 lines (1,401 loc) • 43.5 kB
Markdown
This guide provides comprehensive documentation for error handling patterns, response formats, and troubleshooting techniques used throughout the Firewalla MCP Server.
- [Overview](
- [Error Response Format](
- [Error Types](
- [HTTP Status Codes](
- [Validation Errors](
- [Timeout vs Validation Error Patterns](
- [Common Error Scenarios](
- [Error Recovery Strategies](
- [Best Practices](
- [Troubleshooting Guide](
- [Tool-Specific Errors](
- [Debugging Techniques](
- [Specific Fix Scenarios](
The Firewalla MCP Server implements a comprehensive error handling system designed to provide clear, actionable error messages while maintaining security. All errors follow a standardized format to ensure consistent handling across all tools and integrations.
1. **Clarity**: Error messages are descriptive and actionable
2. **Security**: Sensitive information is not exposed in error messages
3. **Consistency**: All tools use the same error format and patterns
4. **Context**: Errors include relevant context for debugging
5. **Recovery**: Errors suggest recovery strategies when possible
All error responses follow this standardized format:
```typescript
interface StandardError {
error: true; // Always true for error responses
message: string; // Human-readable error description
tool: string; // Name of the tool that generated the error
errorType: ErrorType; // Specific error category
details?: Record<string, unknown>; // Additional error context
validation_errors?: string[]; // Array of validation error messages
timestamp?: string; // ISO timestamp when error occurred
context?: { // Optional request context
endpoint?: string; // API endpoint that failed
parameters?: Record<string, unknown>; // Request parameters (sanitized)
userAgent?: string; // User agent string
requestId?: string; // Unique request identifier
};
}
```
```json
{
"error": true,
"message": "Query contains potentially dangerous content",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Query contains potentially dangerous content"
],
"timestamp": "2024-01-15T10:30:45.123Z",
"context": {
"endpoint": "/v2/boxes/abc123/flows",
"parameters": {
"query": "severity:high",
"limit": 100
},
"requestId": "req_7f8a9b2c"
}
}
```
Error responses are wrapped in the MCP protocol format:
```json
{
"content": [
{
"type": "text",
"text": "{...error object...}"
}
],
"isError": true
}
```
The server categorizes errors into specific types for better handling:
```typescript
enum ErrorType {
VALIDATION_ERROR = 'validation_error', // Parameter validation failures
AUTHENTICATION_ERROR = 'authentication_error', // Auth/credentials issues
API_ERROR = 'api_error', // Firewalla API errors
NETWORK_ERROR = 'network_error', // Network connectivity issues
TIMEOUT_ERROR = 'timeout_error', // Request timeout errors
RATE_LIMIT_ERROR = 'rate_limit_error', // API rate limiting
CACHE_ERROR = 'cache_error', // Cache operation failures
CORRELATION_ERROR = 'correlation_error', // Cross-reference failures
SEARCH_ERROR = 'search_error', // Search operation failures
UNKNOWN_ERROR = 'unknown_error' // Unexpected errors
}
```
```json
{
"error": true,
"message": "limit parameter is required",
"tool": "get_active_alarms",
"errorType": "validation_error",
"validation_errors": ["limit is required"],
"timestamp": "2024-01-15T10:30:45Z"
}
```
```json
{
"error": true,
"message": "Authentication failed. Please check your MSP token.",
"tool": "search_flows",
"errorType": "authentication_error",
"context": {
"endpoint": "/v2/boxes/abc123/flows"
},
"timestamp": "2024-01-15T10:30:45Z"
}
```
```json
{
"error": true,
"message": "Firewalla API returned an error: Box not found",
"tool": "get_device_status",
"errorType": "api_error",
"details": {
"apiStatusCode": 404,
"apiResponse": "Box with ID 'invalid123' not found"
},
"timestamp": "2024-01-15T10:30:45Z"
}
```
```json
{
"error": true,
"message": "API rate limit exceeded. Please wait before making additional requests.",
"tool": "search_alarms",
"errorType": "rate_limit_error",
"details": {
"retryAfter": 60,
"rateLimit": "100 requests per minute"
},
"timestamp": "2024-01-15T10:30:45Z"
}
```
The server maps HTTP status codes to appropriate error types and messages:
| HTTP Code | Error Type | Description | Common Causes |
|-----------|------------|-------------|---------------|
| 400 | validation_error | Bad Request | Invalid parameters, malformed queries |
| 401 | authentication_error | Unauthorized | Invalid or expired MSP token |
| 403 | authentication_error | Forbidden | Insufficient permissions |
| 404 | api_error | Not Found | Invalid box ID, non-existent resource |
| 409 | api_error | Conflict | Resource state conflict |
| 429 | rate_limit_error | Too Many Requests | API rate limit exceeded |
| 500 | api_error | Internal Server Error | Firewalla API issues |
| 502 | network_error | Bad Gateway | MSP service unavailable |
| 503 | network_error | Service Unavailable | Temporary service outage |
| 504 | timeout_error | Gateway Timeout | Request timeout |
```json
{
"error": true,
"message": "Invalid query syntax: unmatched parentheses",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Unmatched parentheses in query"
]
}
```
```json
{
"error": true,
"message": "Authentication failed. Please check your MSP token.",
"tool": "get_active_alarms",
"errorType": "authentication_error",
"details": {
"hint": "Verify FIREWALLA_MSP_TOKEN environment variable is set correctly"
}
}
```
```json
{
"error": true,
"message": "Box not found: invalid-box-id",
"tool": "get_device_status",
"errorType": "api_error",
"details": {
"boxId": "invalid-box-id",
"hint": "Verify FIREWALLA_BOX_ID environment variable is correct"
}
}
```
The server performs extensive parameter validation to ensure data integrity and security.
```json
{
"error": true,
"message": "limit parameter is required",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": ["limit is required"]
}
```
```json
{
"error": true,
"message": "limit must be a number, got string",
"tool": "get_active_alarms",
"errorType": "validation_error",
"validation_errors": [
"limit must be a number, got string"
]
}
```
```json
{
"error": true,
"message": "limit is too large (got 50000, maximum: 10000 for performance reasons)",
"tool": "search_devices",
"errorType": "validation_error",
"validation_errors": [
"limit exceeds system limits to control result set size and prevent memory issues (got 50000, maximum: 10000)"
]
}
```
```json
{
"error": true,
"message": "Invalid query syntax",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Unmatched parentheses in query",
"Unmatched double quotes in query"
]
}
```
```json
{
"error": true,
"message": "Query contains potentially dangerous content",
"tool": "search_alarms",
"errorType": "validation_error",
"validation_errors": [
"Query contains potentially dangerous content"
]
}
```
```json
{
"error": true,
"message": "Field 'invalid_field' is not allowed. Valid fields: source_ip, destination_ip, protocol, severity",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Field 'invalid_field' is not allowed"
]
}
```
```json
{
"error": true,
"message": "Failed to decode cursor: Invalid cursor format",
"tool": "get_device_status",
"errorType": "validation_error",
"validation_errors": [
"Failed to decode cursor: Invalid cursor format"
]
}
```
```json
{
"error": true,
"message": "Failed to decode cursor: Invalid cursor offset",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Invalid cursor offset"
]
}
```
Understanding when different error types occur is crucial for proper error handling and user experience. This section documents the specific patterns and triggers for timeout versus validation errors.
| Condition | Error Type | Response Time | User Action |
|-----------|------------|---------------|-------------|
| Invalid parameter format | validation_error | Immediate (<50ms) | Fix parameter syntax |
| Parameter out of range | validation_error | Immediate (<50ms) | Adjust parameter value |
| Query syntax error | validation_error | Fast (50-200ms) | Fix query syntax |
| Large dataset processing | timeout_error | Slow (>10s) | Reduce scope or use pagination |
| Network connectivity | timeout_error | Variable (5-30s) | Check network/retry |
| API rate limiting | rate_limit_error | Fast (100-500ms) | Wait and retry |
| Invalid credentials | authentication_error | Fast (200-1000ms) | Fix authentication |
**Trigger Conditions**:
- Query returns >10,000 potential results before filtering
- Complex correlation analysis on >5,000 entities
- Geographic enrichment on >2,000 flows
- Bandwidth analysis on >1,000 devices
**Example Scenarios**:
```json
{
"error": true,
"message": "Query timeout: Dataset too large for processing within 10 second limit",
"tool": "search_flows",
"errorType": "timeout_error",
"details": {
"timeout": 10000,
"estimated_results": 25000,
"suggestion": "Use more specific filters: add time range (timestamp:>NOW-1h), protocol filter, or reduce limit to 500"
},
"context": {
"query": "severity:high",
"limit": 2000,
"processing_time": 10001
}
}
```
**Prevention Patterns**:
```bash
// High-risk queries (likely to timeout)
search_flows query:"protocol:tcp" limit:2000 // Too broad
search_alarms query:"severity:>=low" limit:1000 // Includes low-severity
get_bandwidth_usage period:"30d" limit:1000 // Long time period
// Optimized alternatives
search_flows query:"protocol:tcp AND timestamp:>NOW-1h" limit:500
search_alarms query:"severity:>=medium" limit:500
get_bandwidth_usage period:"24h" limit:500
```
**Trigger Conditions**:
- MSP API unavailable or slow
- Network connectivity issues
- DNS resolution failures
- Firewall blocking connections
**Example Error Response**:
```json
{
"error": true,
"message": "Network timeout: Failed to connect to Firewalla MSP API within 30 seconds",
"tool": "get_device_status",
"errorType": "timeout_error",
"details": {
"endpoint": "https://yourdomain.firewalla.net/v2/boxes/abc123/devices",
"timeout": 30000,
"network_error": "ETIMEDOUT",
"retry_suggested": true
},
"context": {
"attempt": 1,
"max_retries": 3
}
}
```
**Network Timeout Detection**:
```typescript
// Timeout patterns by response time
const timeoutPatterns = {
immediate_failure: '0-100ms', // Connection refused, DNS failure
connection_timeout: '5-30s', // Network connectivity issues
read_timeout: '30s+', // API processing issues
processing_timeout: '10s', // Server-side timeout (our limit)
}
```
**Trigger Conditions**:
- Complex cross-reference correlation
- Large geographic dataset enrichment
- Statistical analysis on massive datasets
- Multiple concurrent heavy operations
**Example Error Response**:
```json
{
"error": true,
"message": "Processing timeout: Cross-reference correlation exceeded 10 second processing limit",
"tool": "search_enhanced_cross_reference",
"errorType": "timeout_error",
"details": {
"correlation_fields": ["source_ip", "destination_ip", "country"],
"primary_results": 5000,
"secondary_results": 8000,
"processing_stage": "fuzzy_matching",
"suggestion": "Reduce result sets or use simpler correlation fields"
}
}
```
**Trigger Conditions**:
- Invalid parameter types
- Missing required parameters
- Malformed parameter values
- Invalid enum values
**Response Characteristics**:
- **Response Time**: <50ms (immediate)
- **Error Location**: Client-side validation
- **Recovery**: Fix parameter and retry
**Example Errors**:
```json
{
"error": true,
"message": "limit must be a number between 1 and 1000, got string 'abc'",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"limit parameter must be a number",
"limit must be between 1 and 1000"
],
"details": {
"parameter": "limit",
"received_value": "abc",
"expected_type": "number",
"valid_range": "1-1000"
}
}
```
**Trigger Conditions**:
- Unmatched parentheses or quotes
- Invalid field names
- Malformed operators
- Dangerous query content
**Response Characteristics**:
- **Response Time**: 50-200ms (query parsing)
- **Error Location**: Query validation layer
- **Recovery**: Fix query syntax and retry
**Common Query Syntax Errors**:
```typescript
const querySyntaxErrors = {
unmatched_parentheses: {
query: "severity:high AND (protocol:tcp",
error: "Unmatched parentheses in query"
},
unmatched_quotes: {
query: 'severity:"high AND protocol:tcp',
error: "Unmatched double quotes in query"
},
invalid_field: {
query: "invalid_field:value",
error: "Field 'invalid_field' is not allowed. Valid fields: source_ip, destination_ip, protocol, severity"
},
dangerous_content: {
query: "severity:<script>alert('xss')</script>",
error: "Query contains potentially dangerous content"
}
}
```
**Trigger Conditions**:
- Invalid time ranges (start > end)
- Incompatible parameter combinations
- Resource not found
- Invalid cursor values
**Response Characteristics**:
- **Response Time**: 100-500ms (business logic validation)
- **Error Location**: Business logic layer
- **Recovery**: Adjust parameters to valid combinations
**Example Business Logic Errors**:
```json
{
"error": true,
"message": "Invalid time range: start time must be before end time",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Start time (2024-01-31T00:00:00Z) must be before end time (2024-01-01T00:00:00Z)"
],
"details": {
"start_time": "2024-01-31T00:00:00Z",
"end_time": "2024-01-01T00:00:00Z",
"time_diff": "-30 days"
}
}
```
```typescript
// Error classification logic
function classifyError(error: any, context: any): ErrorType {
// Immediate validation (no API call made)
if (context.stage === 'parameter_validation') {
return ErrorType.VALIDATION_ERROR;
}
// Network-related timeouts
if (error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED') {
return ErrorType.TIMEOUT_ERROR;
}
// API processing timeouts
if (context.processing_time > 10000) {
return ErrorType.TIMEOUT_ERROR;
}
// Query syntax issues
if (context.stage === 'query_parsing' && error.message.includes('syntax')) {
return ErrorType.VALIDATION_ERROR;
}
// Rate limiting
if (error.status === 429) {
return ErrorType.RATE_LIMIT_ERROR;
}
// Authentication issues
if (error.status === 401 || error.status === 403) {
return ErrorType.AUTHENTICATION_ERROR;
}
// Default to API error for other cases
return ErrorType.API_ERROR;
}
```
1. **Large Search Operations**:
```bash
// These queries frequently timeout
search_flows query:"timestamp:>NOW-7d" limit:2000
search_alarms query:"severity:>=low" limit:1000
search_devices query:"online:true" limit:2000
```
2. **Complex Correlation Queries**:
```bash
// Cross-reference operations with large datasets
search_enhanced_cross_reference primary_query:"protocol:tcp" secondary_queries:["severity:high"] limit:5000
```
3. **Bandwidth Analysis on Large Networks**:
```bash
// Heavy processing operations
get_bandwidth_usage period:"30d" limit:1000
```
```typescript
// Progressive query refinement to avoid timeouts
const timeoutPrevention = {
start_small: {
initial_query: "severity:high",
initial_limit: 100,
if_successful: "increase limit gradually"
},
add_filters: {
time_filter: "timestamp:>NOW-1h",
protocol_filter: "protocol:tcp",
geographic_filter: "country:China"
},
use_pagination: {
first_request: { limit: 500, cursor: undefined },
subsequent_requests: { limit: 500, cursor: "from_previous_response" }
}
}
```
1. **Parameter Type Errors**:
```bash
// These cause immediate validation errors
search_flows query:"severity:high" limit:"invalid" // Non-numeric limit
get_device_status limit:-1 // Negative limit
search_alarms query:123 // Non-string query
```
2. **Parameter Range Errors**:
```bash
// Out of range parameters
search_flows limit:50000 // Exceeds maximum
get_bandwidth_usage limit:0 // Below minimum
```
1. **Syntax Errors**:
```bash
// Malformed queries
search_flows query:"severity:high AND (protocol:tcp" // Unmatched parentheses
search_alarms query:"severity:\"high" // Unmatched quotes
```
2. **Field Validation**:
```bash
// Invalid field names
search_flows query:"invalid_field:value" // Unknown field
search_devices query:"non_existent:data" // Field doesn't exist
```
```typescript
const errorResponseTimes = {
validation_error: {
parameter_validation: '10-50ms', // Immediate client-side checks
query_syntax: '50-200ms', // Query parsing and validation
business_logic: '100-500ms', // Complex validation rules
},
timeout_error: {
network_timeout: '5000-30000ms', // Network connectivity issues
processing_timeout: '10000ms+', // Server processing limits
api_timeout: '30000ms+', // External API timeouts
},
rate_limit_error: {
detection: '100-500ms', // Quick API response
recovery: '60000ms+', // Wait time before retry
}
}
```
```json
{
"error": true,
"message": "Missing required configuration: FIREWALLA_MSP_TOKEN",
"tool": "firewalla_client",
"errorType": "authentication_error",
"details": {
"requiredVars": ["FIREWALLA_MSP_TOKEN", "FIREWALLA_MSP_ID", "FIREWALLA_BOX_ID"]
}
}
```
```json
{
"error": true,
"message": "Invalid box configuration: Box ID format is invalid",
"tool": "get_active_alarms",
"errorType": "authentication_error",
"details": {
"hint": "Box ID should be a UUID format like '1eb71e38-3a95-4371-8903-ace24c83ab49'"
}
}
```
```json
{
"error": true,
"message": "Request timeout: Failed to connect to Firewalla MSP API",
"tool": "search_flows",
"errorType": "timeout_error",
"details": {
"timeout": 30000,
"endpoint": "https://yourdomain.firewalla.net/v2/boxes/abc123/flows"
}
}
```
```json
{
"error": true,
"message": "Network error: Unable to reach Firewalla MSP API",
"tool": "get_device_status",
"errorType": "network_error",
"details": {
"networkError": "ENOTFOUND",
"host": "yourdomain.firewalla.net"
}
}
```
```json
{
"error": true,
"message": "Query timeout: Dataset too large for processing",
"tool": "search_flows",
"errorType": "timeout_error",
"details": {
"suggestion": "Use more specific filters or smaller limit values"
}
}
```
```json
{
"error": true,
"message": "Memory limit exceeded during data processing",
"tool": "get_bandwidth_usage",
"errorType": "api_error",
"details": {
"suggestion": "Reduce the time range or limit parameter"
}
}
```
```typescript
async function retryWithBackoff<T>(
operation: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
lastError = error as Error;
// Don't retry validation errors
if (error.errorType === 'validation_error') {
throw error;
}
// Don't retry authentication errors
if (error.errorType === 'authentication_error') {
throw error;
}
// Retry network and timeout errors
if (attempt < maxRetries &&
(error.errorType === 'network_error' ||
error.errorType === 'timeout_error' ||
error.errorType === 'rate_limit_error')) {
const delay = baseDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
throw lastError!;
}
```
```typescript
async function handleRateLimit<T>(operation: () => Promise<T>): Promise<T> {
try {
return await operation();
} catch (error) {
if (error.errorType === 'rate_limit_error') {
const retryAfter = error.details?.retryAfter || 60;
console.log(`Rate limit exceeded. Waiting ${retryAfter} seconds...`);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
// Retry the operation
return await operation();
}
throw error;
}
}
```
```typescript
async function paginateWithCursorRecovery<T>(
searchFunction: (params: any) => Promise<any>,
query: string,
limit: number
): Promise<T[]> {
let cursor: string | undefined;
let allResults: T[] = [];
while (true) {
try {
const response = await searchFunction({ query, limit, cursor });
allResults.push(...response.results);
if (!response.next_cursor) break;
cursor = response.next_cursor;
} catch (error) {
if (error.errorType === 'validation_error' &&
error.message.includes('cursor')) {
console.log('Invalid cursor detected, restarting pagination...');
cursor = undefined; // Reset to beginning
continue;
}
throw error;
}
}
return allResults;
}
```
```typescript
// Good: Comprehensive error handling
async function robustSearch(query: string, limit: number) {
try {
const response = await searchFlows({ query, limit });
return response;
} catch (error) {
// Log the full error for debugging
console.error('Search failed:', error);
// Handle specific error types
switch (error.errorType) {
case 'validation_error':
throw new Error(`Invalid search parameters: ${error.message}`);
case 'authentication_error':
throw new Error('Authentication failed. Please check your credentials.');
case 'rate_limit_error':
throw new Error(`Rate limit exceeded. Please wait ${error.details?.retryAfter || 60} seconds.`);
case 'network_error':
throw new Error('Network error. Please check your connection.');
default:
throw new Error(`Search failed: ${error.message}`);
}
}
}
```
```typescript
// Good: Validate parameters before making API calls
function validateSearchParams(params: SearchParams): string[] {
const errors: string[] = [];
if (!params.query || typeof params.query !== 'string') {
errors.push('Query is required and must be a string');
}
if (!params.limit || typeof params.limit !== 'number') {
errors.push('Limit is required and must be a number');
} else if (params.limit < 1 || params.limit > 10000) {
errors.push('Limit must be between 1 and 10000');
}
if (params.sort_order && !['asc', 'desc'].includes(params.sort_order)) {
errors.push('Sort order must be either "asc" or "desc"');
}
return errors;
}
async function safeSearch(params: SearchParams) {
const validationErrors = validateSearchParams(params);
if (validationErrors.length > 0) {
throw {
error: true,
message: 'Validation failed',
errorType: 'validation_error',
validation_errors: validationErrors
};
}
return await searchFlows(params);
}
```
```typescript
// Good: Provide fallback behavior
async function getDeviceListWithFallback(limit: number = 100) {
try {
// Try to get devices with detailed information
return await getDeviceStatus({ limit });
} catch (error) {
if (error.errorType === 'timeout_error' || error.errorType === 'rate_limit_error') {
console.warn('Full device list unavailable, trying simplified approach...');
// Fallback to smaller request
try {
return await getDeviceStatus({ limit: Math.min(limit, 50) });
} catch (fallbackError) {
console.error('Fallback also failed:', fallbackError);
// Return empty result rather than crashing
return { results: [], count: 0, total_count: 0, has_more: false };
}
}
throw error;
}
}
```
```bash
// Verify environment variables
echo $FIREWALLA_MSP_TOKEN
echo $FIREWALLA_MSP_ID
echo $FIREWALLA_BOX_ID
// Test basic connectivity
curl -H "Authorization: Token $FIREWALLA_MSP_TOKEN" \
"https://$FIREWALLA_MSP_ID/v2/boxes/$FIREWALLA_BOX_ID/alarms?limit=1"
```
```typescript
// Test parameter validation
const testParams = {
query: "severity:high",
limit: 50,
sort_by: "timestamp",
sort_order: "desc"
};
console.log('Testing parameters:', JSON.stringify(testParams, null, 2));
```
```typescript
// Start with the simplest possible query
try {
const response = await searchFlows({
query: "protocol:tcp",
limit: 10
});
console.log('Simple query succeeded:', response.count);
} catch (error) {
console.error('Simple query failed:', error);
}
```
```typescript
// Test network connectivity
async function testConnectivity() {
try {
const response = await fetch(`https://${process.env.FIREWALLA_MSP_ID}/health`);
console.log('MSP API reachable:', response.status);
} catch (error) {
console.error('MSP API unreachable:', error.message);
}
}
```
```typescript
// Debug authentication
async function debugAuth() {
const token = process.env.FIREWALLA_MSP_TOKEN;
const mspId = process.env.FIREWALLA_MSP_ID;
if (!token) {
console.error('FIREWALLA_MSP_TOKEN not set');
return;
}
if (!mspId) {
console.error('FIREWALLA_MSP_ID not set');
return;
}
// Test token format
if (token.length < 20) {
console.warn('Token seems too short, check if complete');
}
// Test MSP domain format
if (!mspId.includes('.firewalla.net')) {
console.warn('MSP ID should end with .firewalla.net');
}
}
```
```typescript
// Debug query syntax
function debugQuery(query: string) {
// Check basic structure
const openParens = (query.match(/\(/g) || []).length;
const closeParens = (query.match(/\)/g) || []).length;
if (openParens !== closeParens) {
console.error('Unmatched parentheses:', { openParens, closeParens });
}
// Check for dangerous patterns
const dangerousPatterns = [
/[<>]/, // Potential injection
/javascript:/i,
/script/i
];
for (const pattern of dangerousPatterns) {
if (pattern.test(query)) {
console.warn('Query contains potentially dangerous pattern:', pattern);
}
}
console.log('Query structure check passed');
}
```
```json
{
"error": true,
"message": "Flow search failed: Invalid time range",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Start time must be before end time"
],
"details": {
"timeRange": {
"start": "2024-01-31T00:00:00Z",
"end": "2024-01-01T00:00:00Z"
}
}
}
```
```json
{
"error": true,
"message": "Device search failed: Network ID not found",
"tool": "search_devices",
"errorType": "api_error",
"details": {
"networkId": "invalid-network-123"
}
}
```
```json
{
"error": true,
"message": "Failed to pause rule: Rule not found",
"tool": "pause_rule",
"errorType": "api_error",
"details": {
"ruleId": "nonexistent-rule-123"
}
}
```
```json
{
"error": true,
"message": "Failed to resume rule: Rule is not currently paused",
"tool": "resume_rule",
"errorType": "api_error",
"details": {
"ruleId": "active-rule-456",
"currentStatus": "active"
}
}
```
```typescript
// Comprehensive error logging
function logError(error: any, context: string) {
const errorLog = {
timestamp: new Date().toISOString(),
context,
error: {
message: error.message,
type: error.errorType || 'unknown',
tool: error.tool || 'unknown',
stack: error.stack,
details: error.details || {}
}
};
console.error('ERROR:', JSON.stringify(errorLog, null, 2));
}
```
```typescript
// Track error patterns
class ErrorMonitor {
private errorCounts = new Map<string, number>();
recordError(error: any) {
const key = `${error.tool}:${error.errorType}`;
const count = this.errorCounts.get(key) || 0;
this.errorCounts.set(key, count + 1);
}
getErrorStats() {
return Object.fromEntries(this.errorCounts);
}
getMostCommonErrors(limit: number = 10) {
return Array.from(this.errorCounts.entries())
.sort(([,a], [,b]) => b - a)
.slice(0, limit);
}
}
```
```typescript
// Test different error scenarios
async function testErrorScenarios() {
const testCases = [
{
name: 'Invalid limit',
params: { query: 'severity:high', limit: -1 },
expectedError: 'validation_error'
},
{
name: 'Invalid query syntax',
params: { query: 'severity:high AND (protocol:tcp', limit: 50 },
expectedError: 'validation_error'
},
{
name: 'Invalid cursor',
params: { query: 'severity:high', limit: 50, cursor: 'invalid' },
expectedError: 'validation_error'
}
];
for (const testCase of testCases) {
try {
await searchFlows(testCase.params);
console.error(`Test '${testCase.name}' should have failed`);
} catch (error) {
if (error.errorType === testCase.expectedError) {
console.log(`Test '${testCase.name}' passed`);
} else {
console.error(`Test '${testCase.name}' failed: expected ${testCase.expectedError}, got ${error.errorType}`);
}
}
}
}
```
The following section documents specific fix scenarios that have been implemented to resolve common issues and prevent regressions. These scenarios provide examples of real-world problems and their solutions.
**Issue**: Tools were accepting null/undefined values for required parameters, causing unpredictable behavior and poor error messages.
**Before Fix**:
```json
{
"query": null,
"limit": undefined
}
// Result: Unpredictable behavior or unclear errors
```
**After Fix**:
```json
{
"error": true,
"message": "limit parameter is required",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"query is required",
"limit is required"
]
}
```
**Prevention Strategy**:
- All required parameters are validated before processing
- Clear error messages specify which parameters are missing
- Null/undefined values are properly detected and rejected
**Issue**: Geographic filters only accepted single values instead of arrays, limiting query flexibility.
**Before Fix**:
```javascript
// Only single country supported
{ countries: "China" } // Limited functionality
```
**After Fix**:
```javascript
// Multiple countries with OR logic
{ countries: ["China", "Russia", "Iran"] }
// Generates: (country:China OR country:Russia OR country:Iran)
```
**Error Prevention**:
```json
{
"error": true,
"message": "Invalid geographic filter: countries must be an array of strings",
"tool": "search_flows_by_geography",
"errorType": "validation_error",
"details": {
"received_type": "string",
"expected_type": "array",
"suggestion": "Use array format: { countries: [\"China\", \"Russia\"] }"
}
}
```
**Issue**: Some parameter validation errors were incorrectly classified as timeout errors, causing user confusion.
**Before Fix**:
```json
{
"error": true,
"message": "Operation timed out",
"errorType": "timeout_error"
}
// When the real issue was a missing required parameter
```
**After Fix**:
```json
{
"error": true,
"message": "limit parameter is required",
"tool": "search_flows",
"errorType": "validation_error",
"details": {
"stage": "parameter_validation",
"response_time": "5ms",
"recovery_type": "immediate",
"fix_required": true
}
}
```
**Classification Logic**:
- Parameters validated in < 100ms → `validation_error`
- Network operations > 10s → `timeout_error`
- Processing operations > 10s → `timeout_error`
- Authentication issues → `authentication_error`
**Issue**: Invalid country codes were accepted or caused errors instead of being normalized to safe defaults.
**Before Fix**:
```javascript
// These inputs caused various issues:
{ country_code: "USA" } // Too long, should be 2 chars
{ country_code: null } // Caused null reference errors
{ country_code: "" } // Empty string accepted as valid
{ country_code: 123 } // Number treated as valid
```
**After Fix**:
```javascript
// All invalid inputs normalize to 'UN' (Unknown)
ensureConsistentGeoData({ country_code: "USA" }); // → { country_code: "UN" }
ensureConsistentGeoData({ country_code: null }); // → { country_code: "UN" }
ensureConsistentGeoData({ country_code: "" }); // → { country_code: "UN" }
ensureConsistentGeoData({ country_code: 123 }); // → { country_code: "UN" }
// Valid codes are normalized to uppercase
ensureConsistentGeoData({ country_code: "us" }); // → { country_code: "US" }
```
**Error Response for Invalid Codes**:
```json
{
"error": false,
"message": "Country code normalized",
"details": {
"original_value": "USA",
"normalized_value": "UN",
"reason": "Invalid length (must be 2 characters)",
"valid_examples": ["US", "CN", "RU", "GB"]
}
}
```
**Issue**: Inconsistent field naming and null handling across different data sources.
**Before Fix**:
```javascript
// Inconsistent field names from different APIs
{
"deviceName": "Router1", // camelCase
"device_id": "123", // snake_case
"MacAddress": "aa:bb:cc", // PascalCase
"ip": null, // null value
"Status": undefined // undefined value
}
```
**After Fix**:
```javascript
// Consistent snake_case naming with safe defaults
{
"device_name": "Router1",
"device_id": "123",
"mac_address": "aa:bb:cc",
"ip_address": "unknown", // null → "unknown"
"status": "unknown" // undefined → "unknown"
}
```
**Normalization Error Handling**:
```json
{
"data": { ... },
"normalization_report": {
"modifications": [
{
"field": "ip_address",
"original_value": null,
"normalized_value": "unknown",
"reason": "null_value_replacement"
},
{
"field": "device_name",
"original_value": "deviceName",
"normalized_value": "device_name",
"reason": "field_name_standardization"
}
],
"errors": [],
"warnings": []
}
}
```
**Issue**: Large queries could exceed memory limits or cause system instability.
**Before Fix**:
```javascript
// No limits - could cause system issues
{ query: "protocol:tcp", limit: 100000 } // Too large
```
**After Fix**:
```json
{
"error": true,
"message": "limit is too large (got 100000, maximum: 10000 for performance reasons)",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"limit exceeds system limits to control result set size and prevent memory issues (got 100000, maximum: 10000)"
],
"details": {
"parameter": "limit",
"received_value": 100000,
"maximum_allowed": 10000,
"suggested_alternatives": [
"Use limit: 1000 and pagination",
"Add time filters to reduce dataset size",
"Use more specific query filters"
]
}
}
```
**Issue**: Complex query syntax errors provided poor guidance for fixing the issue.
**Before Fix**:
```json
{
"error": true,
"message": "Query syntax error",
"errorType": "validation_error"
}
```
**After Fix**:
```json
{
"error": true,
"message": "Query syntax error: Unmatched parentheses in query",
"tool": "search_flows",
"errorType": "validation_error",
"validation_errors": [
"Unmatched parentheses in query",
"Missing closing parenthesis after position 25"
],
"details": {
"query": "severity:high AND (protocol:tcp",
"error_position": 29,
"error_context": "...(protocol:tcp<HERE>",
"suggestions": [
"Add closing parenthesis: severity:high AND (protocol:tcp)",
"Remove opening parenthesis: severity:high AND protocol:tcp",
"Check parentheses balance throughout query"
],
"corrected_examples": [
"severity:high AND (protocol:tcp OR protocol:udp)",
"severity:high AND protocol:tcp"
]
}
}
```
```typescript
// Standardized validation pipeline prevents common issues
async function validateAndExecute(tool: string, params: any) {
// Stage 1: Type validation (< 50ms)
const typeValidation = validateParameterTypes(params);
if (!typeValidation.isValid) {
return createValidationError(tool, typeValidation.errors);
}
// Stage 2: Range validation (< 100ms)
const rangeValidation = validateParameterRanges(params);
if (!rangeValidation.isValid) {
return createValidationError(tool, rangeValidation.errors);
}
// Stage 3: Business logic validation (< 500ms)
const businessValidation = validateBusinessLogic(params);
if (!businessValidation.isValid) {
return createValidationError(tool, businessValidation.errors);
}
// Stage 4: Execute with timeout protection
return await executeWithTimeout(tool, params, 10000);
}
```
```typescript
function classifyError(error: any, context: any): ErrorType {
// Immediate validation errors (always validation_error)
if (context.stage === 'parameter_validation' ||
context.stage === 'query_parsing' ||
context.response_time < 100) {
return ErrorType.VALIDATION_ERROR;
}
// Network-related errors
if (error.code === 'ETIMEDOUT' ||
error.code === 'ECONNREFUSED' ||
error.code === 'ENOTFOUND') {
return context.response_time > 10000 ?
ErrorType.TIMEOUT_ERROR :
ErrorType.NETWORK_ERROR;
}
// Processing timeouts
if (context.response_time > 10000 ||
context.processing_time > 10000) {
return ErrorType.TIMEOUT_ERROR;
}
// Authentication issues
if (error.status === 401 || error.status === 403) {
return ErrorType.AUTHENTICATION_ERROR;
}
// Rate limiting
if (error.status === 429) {
return ErrorType.RATE_LIMIT_ERROR;
}
// Default to API error
return ErrorType.API_ERROR;
}
```
```typescript
async function executeWithRecovery(operation: () => Promise<any>) {
try {
return await operation();
} catch (error) {
// Try recovery strategies based on error type
if (error.errorType === 'timeout_error') {
console.warn('Operation timed out, trying with reduced scope...');
return await executeWithReducedScope(operation);
}
if (error.errorType === 'rate_limit_error') {
console.warn('Rate limited, waiting and retrying...');
await delay(error.details?.retry_after || 60000);
return await operation();
}
if (error.errorType === 'network_error') {
console.warn('Network error, retrying with backoff...');
return await retryWithBackoff(operation, 3);
}
// No recovery possible for validation or auth errors
throw error;
}
}
```
This comprehensive error handling guide provides everything you need to understand, handle, and debug errors in the Firewalla MCP Server. The specific fix scenarios document real-world issues and their solutions, helping prevent regressions and improve error handling consistency. Always check error types and validation messages to understand the root cause and implement appropriate recovery strategies.