PaddlePaddle/PaddleOCR · critical · AuthError

Authentication failed

Error message

Authentication failed: ${text}

What it means

AuthError is thrown when the API answers HTTP 401 or 403. The message embeds the server's explanation (extracted from the body's msg/message/errorMsg field when present, else the raw text). It means the request reached the server but the credentials were rejected or lack permission for the operation.

Solutions

  1. Check the key is present and non-empty in the environment where the code actually runs (print its length/prefix, never the value)
  2. Regenerate or refresh the API key/token and update configuration
  3. Confirm the key matches the environment and has the required permissions/scopes for the endpoint you call
  4. For long-running processes, build a fresh client after key rotation instead of reusing an instance holding old credentials

Example fix

try {
  const jobId = await client.submitJson(model, payload);
} catch (e) {
  if (e instanceof AuthError) {
    // re-create client with refreshed credentials and retry once
    const fresh = createClient({ apiKey: await loadFreshToken() });
    return fresh.submitJson(model, payload);
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

function hasUsableKey(key: string | undefined): boolean {
  return typeof key === "string" && key.trim().length >= 20;
}

Type guard

function isAuthError(e: unknown): e is AuthError {
  return e instanceof AuthError;
}

Try / catch

try {
  await client.submitJson(model, payload);
} catch (e) {
  if (e instanceof AuthError) {
    // do NOT retry with the same key: refresh credentials, rebuild client, retry once
    const freshClient = createClient({ apiKey: await refreshCredentials() });
    return freshClient.submitJson(model, payload);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling any authenticated method with an expired, malformed, or revoked API key/token; using a key from one environment against another (test vs prod); a token with scopes that do not cover the requested endpoint; a key that was rotated server-side while still cached in a long-lived client instance.

Common situations: Hardcoded keys rotated by a security policy; tokens expired because the clock drifted or the session TTL passed; environment variables not set in the deployment (empty-string key); free-tier keys hitting a paid-only endpoint; copying examples with placeholder keys.

Understand the failure class

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/e24929eab8a537ac. Report an issue: GitHub.

Appendix: source

Thrown at api_sdk/typescript/src/internal/http.ts:237

      }
      const message = e instanceof Error ? e.message : String(e);
      throw new NetworkError(`Connection failed: ${message}`);
    } finally {
      clearTimeout(timeoutID);
      signal?.removeEventListener("abort", abort);
    }

    if (resp.ok) return resp;

    let text = await resp.text();
    try {
      const payload = JSON.parse(text) as { msg?: string; message?: string; errorMsg?: string };
      text = payload.msg || payload.message || payload.errorMsg || text;
    } catch {
      // Keep raw response text.
    }
    if (resp.status === 401 || resp.status === 403) {
      throw new AuthError(`Authentication failed: ${text}`);
    } else if (resp.status === 400) {
      throw new InvalidRequestError(`Bad request: ${text}`);
    } else if (resp.status === 429) {
      throw new RateLimitError(`Rate limit exceeded: ${text}`);
    } else if (resp.status === 503 || resp.status === 504) {
      throw new ServiceUnavailableError(resp.status, `Service unavailable: ${text}`);
    } else {
      throw new APIError(resp.status, text);
    }
  }
}

function requireJobId(data: SubmitResponse): string {
  if (!data || typeof data.jobId !== "string" || data.jobId.length === 0) {
    throw new ResponseFormatError("Submit response is missing jobId.");
  }
  return data.jobId;
}

View on GitHub (pinned to 2661c7c0ef)