# SatLoc API Error Patterns - Complete Reference **Date:** October 3, 2025 **Purpose:** Document ALL actual SatLoc API error responses discovered through testing **Status:** Based on real API testing with invalid credentials and parameters --- ## Summary The SatLoc API has **THREE DISTINCT error patterns** depending on the type of error: 1. **Authentication Errors** (wrong username/password) 2. **Parameter Validation Errors** (wrong IDs) 3. **Server Errors** (internal failures) **CRITICAL:** Do NOT confuse authentication errors with parameter validation errors! --- ## 1. Authentication Errors ### Test Scenario: AuthenticateAPIUser with Wrong Credentials **Tested Cases:** - Wrong username and password - Empty password - SQL injection attempts - Special characters in credentials **API Response Pattern:** ``` HTTP Status: 400 Status Text: "Invalid Username or Password provide." Response Body: "" (empty string, NOT JSON) Content-Type: text/html; charset=utf-8 ``` **Example Test Result:** ```javascript // Test: Wrong username and password { status: 400, statusText: "Invalid Username or Password provide.", data: "" // Empty string! } ``` **Detection Pattern:** ```javascript function isAuthenticationError(error) { const status = error.response?.status; const statusText = error.response?.statusText || ''; const data = error.response?.data; return status === 400 && data === '' && (statusText.includes('Invalid Username') || statusText.includes('Invalid Password')); } ``` **Handling Strategy:** - Clear authentication cache - Wait 3 seconds (allow for credential propagation) - Retry authentication ONCE with fresh credentials - If retry fails, throw AppAuthError - Worker should retry the task (not send to DLQ) --- ## 2. Parameter Validation Errors ### Test Scenario: API Methods with Wrong IDs **Affected Endpoints:** - `GetAircraftList` - with wrong userId or companyId - `GetAircraftLogs` - with wrong userId or aircraftId - Other data access endpoints **API Response Pattern:** ``` HTTP Status: 400 Status Text: "Bad Request" Response Body: { "message": "The request is invalid." } Content-Type: application/json; charset=utf-8 ``` **Example Test Results:** ```javascript // Test 1: GetAircraftList with wrong userId { status: 400, statusText: "Bad Request", data: { "message": "The request is invalid." } } // Test 2: GetAircraftList with wrong companyId { status: 400, statusText: "Bad Request", data: { "message": "The request is invalid." } } // Test 3: GetAircraftList with empty userId { status: 400, statusText: "Bad Request", data: { "message": "The request is invalid." } } // Test 4: GetAircraftLogs with wrong userId { status: 400, statusText: "Bad Request", data: { "message": "The request is invalid." } } // Test 5: GetAircraftLogs with wrong aircraftId { status: 400, statusText: "Bad Request", data: { "message": "The request is invalid." } } ``` **Detection Pattern:** ```javascript function isParameterValidationError(error) { const status = error.response?.status; const statusText = error.response?.statusText || ''; const data = error.response?.data; return status === 400 && typeof data === 'object' && data.message === 'The request is invalid.' && statusText === 'Bad Request'; } ``` **Handling Strategy:** - Do NOT clear authentication cache (credentials are fine!) - Do NOT retry (the IDs are wrong, retry won't help) - Log error with context (which IDs are wrong) - Return error to caller with clear message - Worker should NOT retry (data issue, not transient) **IMPORTANT:** These are NOT authentication errors! The credentials are valid, but the resource IDs (userId, companyId, aircraftId) don't exist or don't match. --- ## 3. Server Errors ### Test Scenario: API Methods Triggering Server Failures **Affected Endpoints:** - `UploadJobData` - with wrong userId/companyId/aircraftId - Potentially any endpoint under certain conditions **API Response Pattern:** ``` HTTP Status: 500 Status Text: "Internal Server Error" Response Body: "" (empty string) Content-Type: text/html; charset=utf-8 ``` **Example Test Results:** ```javascript // Test 6: UploadJobData with wrong userId and companyId { status: 500, statusText: "Internal Server Error", data: "" // Empty string! } // Test 7: UploadJobData with wrong aircraftId { status: 500, statusText: "Internal Server Error", data: "" // Empty string! } ``` **Special Case - Empty Username in Authentication:** ```javascript // Test: AuthenticateAPIUser with empty username { status: 500, statusText: "Internal Server Error", data: { "message": "An error has occurred." } } ``` **Detection Pattern:** ```javascript function isServerError(error) { const status = error.response?.status; return status >= 500; } ``` **Handling Strategy:** - Log error with full context - Do NOT clear authentication cache (server issue, not credentials) - Allow worker to retry with exponential backoff - If persistent, send alert to monitoring - May be transient (server restart, network issue, etc.) --- ## Error Decision Tree ``` Is error.response.status === 400? ├─ YES: Is response.data an empty string? │ ├─ YES: Does statusText contain "Invalid Username" or "Invalid Password"? │ │ ├─ YES: → AUTHENTICATION ERROR │ │ └─ NO: → Unknown 400 error │ └─ NO: Is response.data.message === "The request is invalid."? │ ├─ YES: → PARAMETER VALIDATION ERROR │ └─ NO: → Unknown 400 error └─ NO: Is error.response.status >= 500? ├─ YES: → SERVER ERROR └─ NO: → Check other status codes (401, 403, 404, etc.) ``` --- ## Implementation in Code ### isAuthError() Method ```javascript /** * Check if error is authentication-related (wrong credentials) * NOT parameter validation (wrong IDs) */ isAuthError(error) { if (!error) return false; // Check if error is AppAuthError (thrown by our authenticate() method) if (error.name === 'AppAuthError' || error.constructor.name === 'AppAuthError') { return true; } const status = error.response?.status; const statusText = (error.response?.statusText || '').toLowerCase(); const responseData = error.response?.data; // Authentication endpoint failure: HTTP 400 + empty string + specific statusText if (status === 400 && responseData === '' && (statusText.includes('invalid username') || statusText.includes('invalid password') || statusText.includes('username or password'))) { return true; } // NOTE: HTTP 400 with JSON response {"message": "The request is invalid."} // is NOT an auth error - it's parameter validation (wrong IDs) // Check error message from our code const message = (error.message || '').toLowerCase(); if (message.includes('authentication failed') || message.includes('wrong_credential') || message.includes('invalid credential')) { return true; } return false; } ``` ### Error Handling in API Methods ```javascript async getAircraftList(customerId) { try { const authData = await this.getCachedAuth(customerId); const response = await axios.get( `${this.config.apiEndpoint}/GetAircraftList`, { params: { userId: authData.userId, companyId: authData.companyId }, ...this.requestConfig } ); return { success: true, aircraft: response.data || [] }; } catch (error) { const status = error.response?.status; const data = error.response?.data; let errorMessage = error.message; // Provide specific error messages based on error type if (status === 400 && typeof data === 'object' && data.message) { errorMessage = `Invalid parameters: ${data.message} (check userId/companyId)`; } else if (status >= 500) { errorMessage = `SatLoc server error: ${error.message}`; } else if (this.isAuthError(error)) { errorMessage = `Authentication failed: ${error.message}`; } pino.debug('SatLoc GetAircraftList failed', `customer=${customerId}, status=${status}, error=${errorMessage}`); return { success: false, error: errorMessage, isAuthError: this.isAuthError(error), isServerError: status >= 500 }; } } ``` --- ## Testing Commands ### Test Authentication Errors ```bash node tests/test_satloc_errors_simple.js ``` ### Test All API Endpoints with Invalid Data ```bash node tests/test_satloc_all_endpoints.js ``` --- ## Key Takeaways 1. **HTTP 400 does NOT always mean authentication error!** - Empty string response + specific statusText = Authentication error - JSON response with "The request is invalid." = Parameter validation error 2. **Parameter validation errors should NOT trigger cache clearing** - The credentials are valid - The resource IDs are wrong - Retrying won't help 3. **Server errors (HTTP 500) may be transient** - Allow worker retry with backoff - Monitor for persistent failures 4. **Always check response body type and content** - Empty string vs JSON object changes the meaning - statusText provides additional context 5. **Test with actual API calls, not assumptions!** - "Standard" REST patterns don't always apply - Each API has its own error conventions --- ## References - Test script: `test_satloc_errors_simple.js` - Authentication errors - Test script: `test_satloc_all_endpoints.js` - All endpoint errors - Implementation: `services/satloc_service.js` - Error detection and handling - Documentation: `docs/SATLOC_API_ACTUAL_BEHAVIOR.md` - Authentication endpoint behavior