agmission/Development/server/docs/SATLOC_ERROR_PATTERNS.md

9.6 KiB

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:

// Test: Wrong username and password
{
  status: 400,
  statusText: "Invalid Username or Password provide.",
  data: ""  // Empty string!
}

Detection Pattern:

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:

// 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:

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:

// 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:

// Test: AuthenticateAPIUser with empty username
{
  status: 500,
  statusText: "Internal Server Error",
  data: {
    "message": "An error has occurred."
  }
}

Detection Pattern:

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

/**
 * 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

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

node tests/test_satloc_errors_simple.js

Test All API Endpoints with Invalid Data

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