返回 Skill 列表
extension
分类: 开发与工程无需 API Key

openevidence-common-errors

诊断并解决常见的OpenEvidence API错误。当遇到错误代码、调试失败的请求或为临床查询实现错误处理时使用。可以通过诸如“openevidence错误”、“openevidence失败”、“修复openevidence”、“openevidence调试”、“openevidence 4xx”、“openevidence 5xx”这样的短语触发。

person作者: jakexiaohubgithub

OpenEvidence Common Errors

Overview

Comprehensive guide to diagnosing and resolving OpenEvidence API errors with healthcare-specific considerations.

Prerequisites

  • OpenEvidence SDK installed
  • Access to application logs
  • Understanding of HTTP status codes

Error Code Reference

Authentication Errors (4xx)

| Code | Error | Cause | Solution | |------|-------|-------|----------| | 401 | Invalid API Key | Key missing, malformed, or revoked | Verify OPENEVIDENCE_API_KEY is set correctly | | 401 | Organization Not Found | Invalid orgId | Check organization ID in dashboard | | 401 | BAA Not Signed | Business Associate Agreement required | Contact compliance@openevidence.com | | 403 | Forbidden | Insufficient permissions or suspended account | Check account status in dashboard | | 403 | IP Not Whitelisted | Request from non-approved IP | Add IP to allowlist in security settings |

Request Errors (4xx)

| Code | Error | Cause | Solution | |------|-------|-------|----------| | 400 | Invalid Query | Malformed request body | Check request schema | | 400 | Query Too Short | Question too brief | Provide more clinical context | | 400 | Invalid Specialty | Unknown specialty code | Use valid specialty from enum | | 404 | Resource Not Found | Invalid consultId or endpoint | Verify ID and URL | | 422 | Unprocessable | Valid JSON but invalid clinical query | Rephrase question | | 429 | Rate Limited | Too many requests | Implement backoff, check quotas |

Server Errors (5xx)

| Code | Error | Cause | Solution | |------|-------|-------|----------| | 500 | Internal Server Error | OpenEvidence backend issue | Retry with backoff, contact support if persists | | 502 | Bad Gateway | Upstream service issue | Wait and retry | | 503 | Service Unavailable | Maintenance or overload | Check status.openevidence.com | | 504 | Gateway Timeout | Request took too long | Simplify query, increase timeout |

Error Handling Implementation

Step 1: Custom Error Classes

// src/openevidence/errors.ts
export class OpenEvidenceError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly statusCode: number,
    public readonly retryable: boolean,
    public readonly originalError?: Error
  ) {
    super(message);
    this.name = 'OpenEvidenceError';
  }

  static fromApiError(error: any): OpenEvidenceError {
    const statusCode = error.response?.status || 500;
    const message = error.response?.data?.message || error.message;
    const code = error.response?.data?.code || 'UNKNOWN_ERROR';

    return new OpenEvidenceError(
      message,
      code,
      statusCode,
      isRetryable(statusCode),
      error
    );
  }
}

export class AuthenticationError extends OpenEvidenceError {
  constructor(message: string, code: string) {
    super(message, code, 401, false);
    this.name = 'AuthenticationError';
  }
}

export class RateLimitError extends OpenEvidenceError {
  constructor(
    message: string,
    public readonly retryAfter: number,
    public readonly limit: number,
    public readonly remaining: number
  ) {
    super(message, 'RATE_LIMITED', 429, true);
    this.name = 'RateLimitError';
  }
}

export class QueryValidationError extends OpenEvidenceError {
  constructor(
    message: string,
    public readonly validationErrors: string[]
  ) {
    super(message, 'VALIDATION_ERROR', 400, false);
    this.name = 'QueryValidationError';
  }
}

function isRetryable(statusCode: number): boolean {
  return statusCode === 429 || statusCode >= 500;
}

Step 2: Error Handler Wrapper

// src/openevidence/error-handler.ts
import {
  OpenEvidenceError,
  AuthenticationError,
  RateLimitError,
  QueryValidationError,
} from './errors';

export async function withErrorHandling<T>(
  operation: () => Promise<T>,
  context?: { operation?: string; queryId?: string }
): Promise<T> {
  try {
    return await operation();
  } catch (error: any) {
    const oeError = classifyError(error);

    // Log for debugging (without PHI)
    console.error(`[OpenEvidence Error]`, {
      code: oeError.code,
      statusCode: oeError.statusCode,
      operation: context?.operation,
      retryable: oeError.retryable,
    });

    throw oeError;
  }
}

function classifyError(error: any): OpenEvidenceError {
  const status = error.response?.status;
  const data = error.response?.data;

  switch (status) {
    case 401:
      return new AuthenticationError(
        data?.message || 'Authentication failed',
        data?.code || 'AUTH_FAILED'
      );

    case 429:
      return new RateLimitError(
        'Rate limit exceeded',
        parseInt(error.response?.headers?.['retry-after'] || '60'),
        parseInt(error.response?.headers?.['x-ratelimit-limit'] || '0'),
        parseInt(error.response?.headers?.['x-ratelimit-remaining'] || '0')
      );

    case 400:
    case 422:
      return new QueryValidationError(
        data?.message || 'Invalid query',
        data?.errors || []
      );

    default:
      return OpenEvidenceError.fromApiError(error);
  }
}

Step 3: Retry Logic with Exponential Backoff

// src/openevidence/retry.ts
import { OpenEvidenceError, RateLimitError } from './errors';

interface RetryConfig {
  maxRetries: number;
  baseDelayMs: number;
  maxDelayMs: number;
  jitterMs: number;
}

const DEFAULT_CONFIG: RetryConfig = {
  maxRetries: 3,
  baseDelayMs: 1000,
  maxDelayMs: 30000,
  jitterMs: 500,
};

export async function withRetry<T>(
  operation: () => Promise<T>,
  config: Partial<RetryConfig> = {}
): Promise<T> {
  const cfg = { ...DEFAULT_CONFIG, ...config };

  for (let attempt = 0; attempt <= cfg.maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      if (!(error instanceof OpenEvidenceError) || !error.retryable) {
        throw error;
      }

      if (attempt === cfg.maxRetries) {
        throw error;
      }

      // Use Retry-After header for rate limits
      let delay: number;
      if (error instanceof RateLimitError && error.retryAfter > 0) {
        delay = error.retryAfter * 1000;
      } else {
        delay = Math.min(
          cfg.baseDelayMs * Math.pow(2, attempt) + Math.random() * cfg.jitterMs,
          cfg.maxDelayMs
        );
      }

      console.log(`Retry ${attempt + 1}/${cfg.maxRetries} after ${delay}ms`);
      await new Promise(r => setTimeout(r, delay));
    }
  }

  throw new Error('Unreachable');
}

Step 4: User-Facing Error Messages

// src/openevidence/error-messages.ts
import { OpenEvidenceError, RateLimitError, QueryValidationError } from './errors';

export function getUserFriendlyMessage(error: OpenEvidenceError): string {
  switch (error.code) {
    case 'AUTH_FAILED':
    case 'INVALID_API_KEY':
      return 'Unable to connect to medical evidence service. Please contact support.';

    case 'BAA_REQUIRED':
      return 'Service configuration required. Please contact your administrator.';

    case 'RATE_LIMITED':
      const rle = error as RateLimitError;
      return `Service temporarily unavailable. Please try again in ${rle.retryAfter} seconds.`;

    case 'VALIDATION_ERROR':
      const qve = error as QueryValidationError;
      return `Please rephrase your clinical question. ${qve.validationErrors.join('. ')}`;

    case 'QUERY_TOO_SHORT':
      return 'Please provide more details about your clinical question.';

    case 'INVALID_SPECIALTY':
      return 'Please select a valid medical specialty.';

    case 'SERVICE_UNAVAILABLE':
      return 'Medical evidence service is temporarily unavailable. Please try again later.';

    default:
      if (error.statusCode >= 500) {
        return 'Medical evidence service is experiencing issues. Please try again later.';
      }
      return 'Unable to process your request. Please try again or contact support.';
  }
}

Output

  • Classified errors with appropriate handling
  • Retry logic for transient failures
  • User-friendly error messages
  • Comprehensive error logging (without PHI)

Diagnostic Commands

Quick Health Check

# Check if OpenEvidence is reachable
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer ${OPENEVIDENCE_API_KEY}" \
  https://api.openevidence.com/health

# Expected: 200

Check Rate Limit Status

curl -s -D - \
  -H "Authorization: Bearer ${OPENEVIDENCE_API_KEY}" \
  https://api.openevidence.com/v1/rate-limit \
  | grep -i "x-ratelimit"

# Headers show current limits

Error Handling

| Error Pattern | Detection | Resolution | |--------------|-----------|------------| | Intermittent 5xx | > 5% error rate | Enable circuit breaker | | Persistent 401 | All requests fail | Rotate API key | | Spike in 429 | Rate limit headers | Implement request queuing | | Timeout errors | P99 > 30s | Check network, simplify queries |

Examples

Complete Error-Handled Query

async function safeClinicalQuery(question: string) {
  try {
    return await withRetry(
      () => withErrorHandling(
        () => client.query({ question, context: { specialty: 'internal-medicine', urgency: 'routine' } }),
        { operation: 'clinical-query' }
      ),
      { maxRetries: 3 }
    );
  } catch (error) {
    if (error instanceof OpenEvidenceError) {
      return {
        success: false,
        error: getUserFriendlyMessage(error),
        code: error.code,
      };
    }
    throw error;
  }
}

Resources

Next Steps

For comprehensive debugging, see openevidence-debug-bundle.