Skip to content

[Feat]: Passthrough http status code in error #317

@kevzzsk

Description

@kevzzsk

Is your feature request related to a problem? Please describe.

When handling errors from @a2a-js/sdk, the underlying HTTP status codes are abstracted away, making it impossible to implement proper error handling logic based on the HTTP response. This limits the ability to differentiate between various failure scenarios that require different handling strategies.

For example, when a server returns HTTP 402 (Payment Required), 401 (Unauthorized), or 503 (Service Unavailable), the application needs to handle each differently, but currently all are wrapped in SDK errors without exposing the status code. This forces developers to treat all HTTP errors identically, losing important context about the failure reason.

For instance:

  • Payment-required services (402) should trigger payment flows, not be treated as errors
  • Authentication failures (401) should prompt re-authentication
  • Rate limiting (429) should implement backoff strategies
  • Server errors (5xx) vs client errors (4xx) require different retry logic

Describe the solution you'd like

Add statusCode and optionally headers properties to all SDK error classes that can originate from HTTP responses:

// Add to base error class or each specific error class
class TaskNotFoundError extends Error {
  statusCode?: number;
  headers?: Record<string, string>;
  cause?: Error;
}

class InvalidAgentResponseError extends Error {
  statusCode?: number;
  headers?: Record<string, string>;
  cause?: Error;
}

class UnsupportedOperationError extends Error {
  statusCode?: number;
  headers?: Record<string, string>;
  cause?: Error;
}

// ... etc for all HTTP-related SDK errors

This would enable proper HTTP-aware error handling across all error types:

try {
  await client.sendMessage(message);
} catch (err) {
  // Check if it's any SDK error with a status code
  if (err instanceof Error && 'statusCode' in err) {
    const statusCode = (err as any).statusCode;
    
    switch (statusCode) {
      case 402:
        // Payment required - handle payment flow
        break;
      case 401:
        // Unauthorized - trigger authentication
        break;
      case 404:
        // TaskNotFoundError with 404 status
        break;
      case 429:
        // Rate limited - implement backoff
        break;
      case 503:
        // Service unavailable - retry later
        break;
      default:
        if (statusCode >= 500) {
          // Server error - treat as temporary failure
        }
    }
  }
}

Why all error classes need this:

Different SDK error types can originate from different HTTP status codes:

  • TaskNotFoundError → 404 Not Found
  • UnsupportedOperationError → 405 Method Not Allowed
  • InvalidAgentResponseError → 400 Bad Request, 402 Payment Required, etc.
  • AuthenticatedExtendedCardNotConfiguredError → 401 Unauthorized, 403 Forbidden

Applications need to handle these based on both the error type (what went wrong) and the status code (how the server categorized it).

Describe alternatives you've considered

The only alternative right now is that server have to parse the error string from the status code.

Additional context

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions