How FreeLLMAPI Handles Error Redaction and Classification to Sanitize Provider Responses

FreeLLMAPI sanitizes raw provider errors through regex-based redaction that strips tokens and secrets, then classifies the sanitized error to determine if the failure is retryable, payment-related, or a model-access issue without exposing sensitive data to logs or clients.

The tashfeenahmed/freellmapi repository implements a strict two-stage pipeline to handle failures from upstream LLM providers. First, it redacts sensitive material from error messages; second, it categorizes the error type to drive fallback logic. This ensures that API keys, bearer tokens, and URLs never leak into analytics or user-facing responses while enabling the system to make intelligent routing decisions.

Error Redaction Pipeline

The redaction layer lives in server/src/lib/error-redaction.ts and provides a single exported function that transforms any thrown value into a safe, truncated string.

Regex Patterns for Sensitive Data Removal

The module defines a REDACTIONS array containing [RegExp, string] pairs that target specific secret patterns:

  • Bearer tokens: /\bBearer\s+[A-Za-z0-9._~+/-]+=*/giBearer [redacted]
  • API keys and secrets: /\b(api[_-]?key|access[_-]?token|token|secret|authorization)(\s*[:=]\s*)(["']?)[^"',\s}\]]+/gi → captures the key name and delimiter, replaces the value with [redacted]
  • OpenAI-style keys: /\bsk-[A-Za-z0-9_-]{8,}\b/g[redacted-key]
  • JWT-like tokens: /\b[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\b/g[redacted-token]
  • URLs: /\bhttps?:\/\/[^\s"'<>)]*/gi[redacted-url] to prevent query-string credential leaks

The sanitizeProviderErrorMessage Function

This utility processes raw errors through a strict normalization sequence:

  1. Converts non-string inputs using String(message ?? '')
  2. Trims whitespace and defaults to "Provider error" if empty
  3. Iterates through the REDACTIONS array, applying each regex replacement
  4. Collapses multiple spaces and trims again
  5. Enforces the MAX_PROVIDER_ERROR_LENGTH constant (240 characters), appending "…" if truncated
import { sanitizeProviderErrorMessage } from '../lib/error-redaction.js';

function handleProviderError(err: unknown) {
  const safe = sanitizeProviderErrorMessage(err);
  console.warn('Provider error (redacted):', safe);
}

Error Classification System

After redaction, the system classifies the original error object to determine downstream handling logic. The pure utility functions reside in server/src/lib/error-classify.ts.

Detecting Retryable Failures

The isRetryableError function examines HTTP status codes and message substrings to decide if a request should be retried on an alternate provider. It returns true for:

  • Status codes: 408, 409, 410, 429, or any 5xx (server errors)
  • Message content: "rate limit", "quota", "timeout", "503", "404" (when transient)

Payment and Access Violations

Three additional functions identify specific failure modes:

  • isPaymentRequiredError: Detects HTTP 402 or messages containing "payment required" or "insufficient_quota" (lines 71–78)
  • isModelNotFoundError: Flags HTTP 404/410 or messages with "not found" or "no endpoints found" (lines 86–95)
  • isModelAccessForbiddenError: Catches HTTP 403 or messages containing "403"/"forbidden" when a key is valid but the model tier is restricted (lines 100–107)

Integration Across the Request Lifecycle

Both libraries are imported wherever provider responses are processed. In server/src/routes/proxy.ts, the functions are imported on lines 13 and 17, then invoked inside catch blocks:

import { sanitizeProviderErrorMessage } from '../lib/error-redaction.js';
import {
  isRetryableError,
  isPaymentRequiredError,
  isModelNotFoundError,
  isModelAccessForbiddenError,
} from '../lib/error-classify.js';

async function proxyRequest(req, res) {
  try {
    // … upstream LLM call …
  } catch (err) {
    const safeMsg = sanitizeProviderErrorMessage(err);
    traceRouteEvent('Proxy', { error: safeMsg });

    if (isRetryableError(err)) {
      await retryWithNextProvider(req, res);
    } else if (isPaymentRequiredError(err)) {
      await benchKeyForPayment(req);
    } else if (isModelNotFoundError(err) || isModelAccessForbiddenError(err)) {
      await skipModel(req);
    } else {
      res.status(502).json({ error: { message: safeMsg } });
    }
  }
}

The same pattern appears in server/src/routes/responses.ts (line 31) and server/src/services/fusion.ts (line 17), ensuring consistent sanitization and logic across the proxy, chat completions endpoint, and fusion panel.

Summary

  • Redaction occurs first: sanitizeProviderErrorMessage in server/src/lib/error-redaction.ts strips bearer tokens, API keys, and URLs using curated regexes, then truncates to 240 characters.
  • Classification follows: Pure functions in server/src/lib/error-classify.ts label errors as retryable, payment-required, model-not-found, or access-forbidden based on HTTP status codes and message substrings.
  • No data leakage: Secrets never reach logs, analytics, or JSON responses because redaction happens before any inspection or transmission.
  • Consistent routing: The proxy, responses route, and fusion service all share the same error-handling utilities, enabling centralized fallback and retry logic.

Frequently Asked Questions

What types of sensitive data does FreeLLMAPI redact from provider errors?

FreeLLMAPI redacts Bearer tokens, OpenAI-style secret keys (sk-...), JWT-like tokens, generic API keys and access tokens, and full URLs. These patterns are defined in the REDACTIONS array within server/src/lib/error-redaction.ts.

How does FreeLLMAPI determine if a provider error is retryable?

The isRetryableError function checks for HTTP status codes 408, 409, 410, 429, or any server error ≥ 500. It also scans the error message for substrings like "rate limit", "quota", "timeout", or "503". If matched, the system routes the request to the next available provider.

What is the maximum length of a sanitized error message in FreeLLMAPI?

The constant MAX_PROVIDER_ERROR_LENGTH caps sanitized messages at 240 characters. Longer strings are truncated and appended with an ellipsis ().

Where does error classification occur in the FreeLLMAPI request pipeline?

Classification occurs in the catch blocks of provider-facing routes and services, specifically in server/src/routes/proxy.ts, server/src/routes/responses.ts, and server/src/services/fusion.ts. These files import the classification utilities to decide whether to retry, bench a key, skip a model, or return the sanitized error to the client.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →