/** * Common Error Patterns for Adapters * * This module provides pre-configured error patterns for common error * scenarios that adapters encounter. These patterns can be used directly * or as a foundation for adapter-specific patterns. * * ## Pattern Categories * - Connection Failures: ECONNREFUSED, ENOTFOUND, ECONNRESET, DNS errors * - Timeouts: Timeout, timed out, ETIMEDOUT * - HTTP Status Errors: 4xx and 5xx status codes * - Protocol Errors: Parse errors, invalid JSON, protocol violations * - SSL/TLS Errors: Certificate validation failures * - Rate Limiting: HTTP 429, rate limit exceeded * - Network Errors: General network connectivity issues * * ## Usage * ```typescript * import { COMMON_ERROR_PATTERNS } from "@wavespec/kit/error"; * import { ErrorMapper } from "@wavespec/kit/error"; * * const mapper = new ErrorMapper({ * defaultCode: "TEST_EXECUTION_ERROR", * defaultHint: "Unexpected error" * }); * * // Add all common patterns * mapper.addPatterns(COMMON_ERROR_PATTERNS); * * // Or add specific patterns * mapper.addPattern(CONNECTION_REFUSED_PATTERN); * ``` * * ## Pattern Order * Patterns are matched in order (first match wins), so specific patterns * are defined before generic ones. This ensures precise error classification. * * @module @wavespec/kit/error */ import type { ErrorPattern } from "./types.js"; import { ERROR_CODES as HARNESS_ERROR_CODES } from "@wavespec/types"; // =================================================================== // CONNECTION ERROR PATTERNS (10 patterns) // =================================================================== /** * Connection refused - server actively rejected connection * * Matches: ECONNREFUSED error codes, "connection refused" messages */ export const CONNECTION_REFUSED_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; const msg = err.message?.toLowerCase() || ""; return err.code === "ECONNREFUSED" || msg.includes("econnrefused") || msg.includes("connection refused"); }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Connection refused: {message}", hint: "The server actively refused the connection. This typically means:\n • The server is not running or has crashed\n • The port number is incorrect\n • A firewall is blocking the connection\n • The server process exited unexpectedly", fix: "Verify the server is running on the correct host and port. Test connectivity manually (e.g., curl, telnet). Check firewall rules. Review server startup logs for crash messages.", severity: "error", extractContext: (error) => ({ code: (error as any).code, syscall: (error as any).syscall, errno: (error as any).errno, }), recovery: { type: "retry", params: { maxAttempts: 3, backoffMs: 1000, }, }, }; /** * Connection reset - connection was forcibly closed by server * * Matches: ECONNRESET error codes, "connection reset" messages */ export const CONNECTION_RESET_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; const msg = err.message?.toLowerCase() || ""; return err.code === "ECONNRESET" || msg.includes("econnreset") || msg.includes("connection reset"); }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Connection reset by peer: {message}", hint: "The server closed the connection unexpectedly. This usually means:\n • The server crashed or restarted\n • The server closed the connection due to inactivity\n • Network path was disrupted", fix: "Check server logs for crashes or restarts. Verify server is still running. Check network connectivity. Retry the operation with backoff.", recovery: { type: "retry", params: { maxAttempts: 2, backoffMs: 2000, }, }, }; /** * DNS resolution failed - hostname could not be resolved * * Matches: ENOTFOUND, GETADDRINFO errors */ export const DNS_RESOLUTION_FAILED_PATTERN: ErrorPattern = { match: /enotfound|getaddrinfo|nodename nor servname provided|name or service not known/i, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "DNS resolution failed: {message}", hint: "The hostname could not be resolved to an IP address. This typically means:\n • The hostname is misspelled\n • The hostname doesn't exist\n • DNS is not working on your network\n • Network connectivity is broken", fix: "Verify the hostname spelling in your configuration. Test DNS resolution manually (e.g., nslookup, dig). Check network connectivity. Verify DNS server is reachable.", recovery: { type: "manual", }, }; /** * Network unreachable - system cannot reach the network * * Matches: ENETUNREACH error code */ export const NETWORK_UNREACHABLE_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; return err.code === "ENETUNREACH"; }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Network unreachable: {message}", hint: "Your system cannot reach the network or the target host is on an unreachable network. This typically means:\n • Your computer is not connected to a network\n • Network interface is down\n • Routing is misconfigured\n • Host is on a network you cannot reach", fix: "Check your network connection. Verify network interface is up (e.g., ifconfig, ipconfig). Check routing table. Verify you can reach the network (ping default gateway).", }; /** * Host unreachable - specific host cannot be reached * * Matches: EHOSTUNREACH error code */ export const HOST_UNREACHABLE_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; return err.code === "EHOSTUNREACH"; }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Host unreachable: {message}", hint: "The specific host is not reachable. This typically means:\n • The host is not connected to the network\n • A router/firewall is blocking traffic to the host\n • The host crashed or powered off\n • Network interface on host is down", fix: "Verify the host is powered on and connected to the network. Check firewall rules. Ping the host to verify it's reachable. Check routing table.", }; /** * Generic connection error - connection failed (catch-all) * * Matches: "connection" in error message (catch-all for other connection errors) */ export const GENERIC_CONNECTION_ERROR_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; const msg = err.message?.toLowerCase() || ""; // Match generic connection errors that don't have specific codes return msg.includes("connection") && !msg.includes("timeout") && !msg.includes("reset") && !msg.includes("refused"); }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Connection error: {message}", hint: "A connection-related error occurred that doesn't match more specific error patterns. Review the error message for details.", fix: "Verify server is running and reachable. Check network connectivity. Review server and client logs for more details.", recovery: { type: "retry", params: { maxAttempts: 2, backoffMs: 1000, }, }, }; // =================================================================== // TIMEOUT ERROR PATTERNS (3 patterns) // =================================================================== /** * Operation timeout - operation exceeded configured timeout * * Matches: "timeout" or "timed out" in message, ETIMEDOUT code */ export const OPERATION_TIMEOUT_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; const msg = err.message?.toLowerCase() || ""; return /timeout|timed out|etimedout/i.test(msg) || err.code === "ETIMEDOUT"; }, code: HARNESS_ERROR_CODES.OPERATION_TIMEOUT.code, messageTemplate: "Operation timed out: {message}", hint: "The operation exceeded the configured timeout limit. This typically means:\n • The server is processing a slow operation\n • The server is experiencing high load\n • Network latency is very high\n • The server is deadlocked or stuck", fix: "Increase the timeout value in your configuration. Profile server performance to identify bottlenecks. Optimize slow operations. Verify server health and resource utilization.", severity: "error", recovery: { type: "retry", params: { maxAttempts: 2, backoffMs: 2000, }, }, }; /** * Request timeout - HTTP request timed out * * Matches: Headers timeout, body timeout, or general timeout */ export const REQUEST_TIMEOUT_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { code?: string }; return ( err.code === "UND_ERR_HEADERS_TIMEOUT" || err.code === "UND_ERR_BODY_TIMEOUT" || err.message?.toLowerCase().includes("timeout") === true ); }, code: HARNESS_ERROR_CODES.OPERATION_TIMEOUT.code, messageTemplate: "HTTP request timed out: {message}", hint: "The HTTP request exceeded its timeout limit while waiting for headers or response body. This typically means:\n • The server is slow to respond\n • Network latency is high\n • Server is stuck or deadlocked\n • Too much data in response", fix: "Increase timeout in adapter config or test spec. Optimize endpoint performance. Reduce response payload size. Verify server performance.", recovery: { type: "retry", params: { maxAttempts: 2, backoffMs: 2000, }, }, }; /** * Connect timeout - connection attempt timed out * * Matches: Connection timeout messages */ export const CONNECT_TIMEOUT_PATTERN: ErrorPattern = { match: /connect.*timeout|connection.*timeout/i, code: HARNESS_ERROR_CODES.OPERATION_TIMEOUT.code, messageTemplate: "Connection timed out: {message}", hint: "Could not establish a connection to the server within the timeout limit. This typically means:\n • The server is not responding\n • Network latency is very high\n • Connection is being blocked by a firewall\n • Server is overloaded", fix: "Verify server is running and accepting connections. Check network connectivity. Increase connection timeout. Check firewall rules.", recovery: { type: "retry", params: { maxAttempts: 3, backoffMs: 1500, }, }, }; // =================================================================== // PROTOCOL ERROR PATTERNS (4 patterns) // =================================================================== /** * JSON parse error - response is not valid JSON * * Matches: SyntaxError, "JSON.parse" errors, "Unexpected token" errors */ export const JSON_PARSE_ERROR_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error; const msg = err.message?.toLowerCase() || ""; const name = err.name?.toLowerCase() || ""; return ( name === "syntaxerror" || msg.includes("unexpected token") || msg.includes("json.parse") || msg.includes("invalid json") ); }, code: HARNESS_ERROR_CODES.INVALID_JSON_RESPONSE.code, messageTemplate: "Failed to parse JSON response: {message}", hint: "The response body is not valid JSON. This typically means:\n • Server returned plain text instead of JSON\n • Response is HTML error page (server error)\n • Response is truncated or corrupted\n • Wrong content-type header", fix: "Verify endpoint returns valid JSON. Check server error logs. Verify response headers (Content-Type should be application/json). Test endpoint with curl or Postman.", }; /** * Invalid response - response missing required fields * * Matches: "invalid response", "malformed", protocol-specific errors */ export const INVALID_RESPONSE_PATTERN: ErrorPattern = { match: /invalid response|malformed|protocol|bad format|unexpected format/i, code: HARNESS_ERROR_CODES.MCP_PROTOCOL_ERROR.code, messageTemplate: "Invalid response received: {message}", hint: "The server returned a response that doesn't conform to the expected protocol format. This typically means:\n • Server implementation doesn't follow the protocol spec\n • Server version is incompatible\n • Response was corrupted in transit\n • Server sent wrong response type", fix: "Verify server implementation follows the protocol specification. Check server version compatibility. Verify network isn't corrupting data. Review server logs.", }; /** * Protocol error - generic protocol violation * * Matches: "protocol", "protocol error", MCP-specific protocol errors */ export const PROTOCOL_ERROR_PATTERN: ErrorPattern = { match: (error) => { const err = error as Error & { name?: string }; const msg = err.message?.toLowerCase() || ""; const name = err.name?.toLowerCase() || ""; return name === "mcperror" || msg.includes("protocol") || msg.includes("protocol error"); }, code: HARNESS_ERROR_CODES.MCP_PROTOCOL_ERROR.code, messageTemplate: "Protocol error: {message}", hint: "A protocol-level error occurred. This typically means:\n • Server doesn't implement the protocol correctly\n • Client and server versions are incompatible\n • Message format is invalid\n • Unexpected message type received", fix: "Review protocol specification. Verify server and client versions are compatible. Check server implementation. Enable protocol tracing/debugging.", }; /** * Unexpected response type - server sent wrong type of response * * Matches: Response type mismatches, unexpected message types */ export const UNEXPECTED_RESPONSE_PATTERN: ErrorPattern = { match: /unexpected|unexpected type|wrong type|invalid type/i, code: HARNESS_ERROR_CODES.MCP_PROTOCOL_ERROR.code, messageTemplate: "Unexpected response type: {message}", hint: "The server sent a response type that wasn't expected. This typically means:\n • Server is in an unexpected state\n • Client and server are out of sync\n • Server version is incompatible\n • Previous request wasn't properly acknowledged", fix: "Verify client and server versions are compatible. Check server state. Review request sequence. Enable debug logging.", }; // =================================================================== // SSL/TLS ERROR PATTERNS (3 patterns) // =================================================================== /** * SSL/TLS certificate validation failed * * Matches: SSL, TLS, certificate, cert errors */ export const SSL_CERTIFICATE_ERROR_PATTERN: ErrorPattern = { match: /ssl|tls|certificate|cert|eacces/i, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "SSL/TLS certificate error: {message}", hint: "SSL/TLS certificate validation failed. This typically means:\n • Certificate is self-signed (not trusted)\n • Certificate has expired\n • Hostname doesn't match certificate\n • Incorrect certificate chain\n • System doesn't trust the certificate authority", fix: "For self-signed certificates, configure client to accept them (set rejectUnauthorized: false, but NOT in production). Verify certificate validity and chain. Update CA certificates if needed.", }; /** * Certificate hostname mismatch * * Matches: "hostname", "host", "name mismatch" in SSL context */ export const CERTIFICATE_HOSTNAME_MISMATCH_PATTERN: ErrorPattern = { match: /hostname|host.*mismatch|mismatch.*host|dnsnamemismatch/i, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Certificate hostname mismatch: {message}", hint: "The certificate's hostname doesn't match the requested hostname. This typically means:\n • Using IP address instead of hostname\n • Wrong domain name\n • Certificate is for different domain\n • Using localhost with production certificate", fix: "Use the correct hostname that matches the certificate. If using IP, switch to hostname. Verify certificate covers the domain you're accessing.", }; /** * Certificate expired * * Matches: "expired", "validity" in SSL context */ export const CERTIFICATE_EXPIRED_PATTERN: ErrorPattern = { match: /expired|not yet valid|validity|cert.*expired/i, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Certificate expired: {message}", hint: "The SSL/TLS certificate has expired or is not yet valid. This typically means:\n • Certificate validity period has ended\n • System time is incorrect\n • Certificate is not yet valid (wrong date)", fix: "Renew the certificate on the server. Verify your system time is correct. Check certificate validity dates with: openssl x509 -in cert.pem -noout -dates", }; // =================================================================== // HTTP STATUS CODE PATTERNS (8 patterns) // =================================================================== /** * HTTP 400 Bad Request - invalid parameters * * Matches: "400" status code */ export const HTTP_400_BAD_REQUEST_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; return err.status === 400 || err.statusCode === 400; }, code: HARNESS_ERROR_CODES.INVALID_TOOL_ARGUMENTS.code, messageTemplate: "Bad Request (400): {message}", hint: "The server rejected the request because it's malformed or has invalid parameters. This typically means:\n • Required parameter is missing\n • Parameter value is invalid\n • Request body is malformed\n • Content-Type header is incorrect", fix: "Review API documentation for required parameters and formats. Verify all required fields are present. Validate parameter values match expected types. Check Content-Type header.", }; /** * HTTP 401 Unauthorized - authentication required * * Matches: "401" status code */ export const HTTP_401_UNAUTHORIZED_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; return err.status === 401 || err.statusCode === 401; }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Unauthorized (401): {message}", hint: "Authentication failed or credentials are missing. This typically means:\n • API key is missing or invalid\n • Bearer token is missing or expired\n • Username/password is wrong\n • Authentication header is malformed", fix: "Verify API key or token is present and correct. Check that Authorization header is properly formatted. Refresh expired tokens. Review authentication configuration.", }; /** * HTTP 403 Forbidden - authenticated but not authorized * * Matches: "403" status code */ export const HTTP_403_FORBIDDEN_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; return err.status === 403 || err.statusCode === 403; }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Forbidden (403): {message}", hint: "You authenticated successfully, but don't have permission to access this resource. This typically means:\n • Your role/account doesn't have required permissions\n • Resource is restricted\n • IP address is blocked\n • API access is not enabled for your plan", fix: "Verify your account has required permissions. Check resource access restrictions. Verify IP is not blocked. Review API plan/subscription restrictions.", }; /** * HTTP 404 Not Found - resource doesn't exist * * Matches: "404" status code */ export const HTTP_404_NOT_FOUND_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; return err.status === 404 || err.statusCode === 404; }, code: HARNESS_ERROR_CODES.TOOL_NOT_FOUND.code, messageTemplate: "Not Found (404): {message}", hint: "The requested resource does not exist. This typically means:\n • Endpoint URL is wrong\n • Resource has been deleted\n • API endpoint doesn't exist\n • Wrong API version", fix: "Verify endpoint URL is correct. Check API documentation for correct paths. Verify resource hasn't been deleted. Verify API version is correct.", }; /** * HTTP 429 Too Many Requests - rate limited * * Matches: "429" status code */ export const HTTP_429_RATE_LIMITED_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; return err.status === 429 || err.statusCode === 429 || /rate.?limit|too.?many.?request/i.test(err.message || ""); }, code: HARNESS_ERROR_CODES.TEST_EXECUTION_ERROR.code, messageTemplate: "Rate Limited (429): {message}", hint: "You've sent too many requests too quickly. The server is enforcing rate limits. This typically means:\n • Sending requests too fast\n • Hitting hourly/daily request quota\n • Concurrent request limit exceeded\n • Test is too aggressive", fix: "Wait before retrying. Implement exponential backoff. Reduce request frequency. Check rate limit headers (Retry-After, X-RateLimit-Reset). Consider upgrading to higher rate limit tier.", recovery: { type: "retry", params: { maxAttempts: 3, backoffMs: 5000, }, }, }; /** * HTTP 500 Internal Server Error - server bug * * Matches: "500" status code */ export const HTTP_500_SERVER_ERROR_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; return err.status === 500 || err.statusCode === 500; }, code: HARNESS_ERROR_CODES.SERVER_ERROR.code, messageTemplate: "Internal Server Error (500): {message}", hint: "The server encountered an unexpected internal error. This indicates a bug in the server code, not a client-side issue. This typically means:\n • Unhandled exception in server\n • Logic bug or edge case\n • Resource exhaustion (memory, disk, connections)\n • Crash in dependent service", fix: "Check server logs for stack traces and error details. Review server implementation for the failing endpoint. Verify request parameters don't trigger edge cases. This is a server bug that needs server-side fixes.", recovery: { type: "retry", params: { maxAttempts: 2, backoffMs: 2000, }, }, }; /** * HTTP 503 Service Unavailable - server temporarily down * * Matches: "502", "503", "504" status codes */ export const HTTP_UNAVAILABLE_PATTERN: ErrorPattern = { match: (error) => { const err = error as any; const status = err.status ?? err.statusCode; return status === 502 || status === 503 || status === 504; }, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Service Unavailable ({status}): {message}", hint: "The server is temporarily unavailable. This typically means:\n • Server is being restarted or redeployed\n • Server is overloaded\n • Upstream service is down (502 Bad Gateway)\n • Server maintenance is in progress", fix: "Wait a moment and retry. Check server status page. Verify upstream services are running. Check server logs for maintenance windows. Implement exponential backoff.", recovery: { type: "retry", params: { maxAttempts: 3, backoffMs: 3000, }, }, }; // =================================================================== // NETWORK ERROR PATTERNS (2 patterns) // =================================================================== /** * Network error - generic network connectivity issue * * Matches: "network" errors that don't match specific patterns */ export const NETWORK_ERROR_PATTERN: ErrorPattern = { match: /network|net|socket/i, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Network error: {message}", hint: "A network-related error occurred. This typically means:\n • Network interface is down\n • Network connectivity is lost\n • Socket error occurred\n • Network packet loss", fix: "Check network connectivity. Verify network interface is up. Ping gateway/DNS server to verify network. Check for network cable/WiFi connection.", }; /** * EOFCONNECTIONS - end of file on socket * * Matches: EOF, FIN, connection closed by peer */ export const EOF_PATTERN: ErrorPattern = { match: /eof|fin|connection.*closed|closed.*connection/i, code: HARNESS_ERROR_CODES.ADAPTER_CONNECTION_FAILED.code, messageTemplate: "Connection closed unexpectedly: {message}", hint: "The server closed the connection without completing the operation. This typically means:\n • Server crashed or restarted\n • Server closed connection due to protocol violation\n • Network interruption\n • Server resource limits exceeded", fix: "Check server logs for crashes. Verify server is still running. Retry the operation. Check network stability.", recovery: { type: "retry", params: { maxAttempts: 2, backoffMs: 1000, }, }, }; // =================================================================== // COLLECTION OF ALL COMMON PATTERNS // =================================================================== /** * Collection of all common error patterns * * These patterns are ordered to ensure specific patterns are matched * before generic ones (first match wins). * * Order: * 1. HTTP status codes (most specific - explicit status code checks) * 2. Timeout errors (specific timeout indicators) * 3. Connection errors * 4. Protocol errors * 5. SSL/TLS errors * 6. Network errors (most generic) * * Adapters can use this directly or create a modified list with * adapter-specific patterns added before or after these patterns. */ export const COMMON_ERROR_PATTERNS: ErrorPattern[] = [ // HTTP status codes - FIRST because they check explicit status code (most specific) HTTP_400_BAD_REQUEST_PATTERN, HTTP_401_UNAUTHORIZED_PATTERN, HTTP_403_FORBIDDEN_PATTERN, HTTP_404_NOT_FOUND_PATTERN, HTTP_429_RATE_LIMITED_PATTERN, HTTP_500_SERVER_ERROR_PATTERN, HTTP_UNAVAILABLE_PATTERN, // Timeout errors - specific timeout patterns OPERATION_TIMEOUT_PATTERN, REQUEST_TIMEOUT_PATTERN, CONNECT_TIMEOUT_PATTERN, // Connection errors - network-level connection issues CONNECTION_REFUSED_PATTERN, CONNECTION_RESET_PATTERN, DNS_RESOLUTION_FAILED_PATTERN, NETWORK_UNREACHABLE_PATTERN, HOST_UNREACHABLE_PATTERN, GENERIC_CONNECTION_ERROR_PATTERN, // Protocol errors JSON_PARSE_ERROR_PATTERN, INVALID_RESPONSE_PATTERN, PROTOCOL_ERROR_PATTERN, UNEXPECTED_RESPONSE_PATTERN, // SSL/TLS errors SSL_CERTIFICATE_ERROR_PATTERN, CERTIFICATE_HOSTNAME_MISMATCH_PATTERN, CERTIFICATE_EXPIRED_PATTERN, // Network errors - most generic last NETWORK_ERROR_PATTERN, EOF_PATTERN, ]; /** * Count of common error patterns * * Useful for documentation and verification. */ export const COMMON_ERROR_PATTERN_COUNT = COMMON_ERROR_PATTERNS.length;