amruthpillai/reactive-resume · error · ORPCError

BAD_GATEWAY

BAD_GATEWAY

Error message

Could not reach the AI provider.

What it means

BAD_GATEWAY thrown by the throwAiProviderGatewayError helper in the AI feature router. It is invoked from each AI handler's catch block when the error is recognized as an AISDKError (isAiProviderGatewayError), i.e. the AI SDK itself surfaced a provider/network/runtime error during generateText. The original error is preserved as cause for server-side reporters.

Source

Thrown at packages/api/src/features/ai/router.ts:28

import { aiProvidersService } from "../ai-providers/service";
import { resumeService } from "../resume/service";
import { aiService, fileInputSchema } from "./service";

function isInvalidAiBaseUrlError(error: unknown): boolean {
	return error instanceof Error && error.message === "INVALID_AI_BASE_URL";
}

function isAiProviderGatewayError(error: unknown): boolean {
	return error instanceof AISDKError;
}

function isCredentialEncryptionUnavailable(error: unknown): boolean {
	return error instanceof Error && error.message === "AI_CREDENTIAL_ENCRYPTION_UNAVAILABLE";
}

/** Throws a BAD_GATEWAY ORPCError, preserving the original cause for upstream error reporters. */
function throwAiProviderGatewayError(cause?: unknown): never {
	throw new ORPCError("BAD_GATEWAY", { message: "Could not reach the AI provider.", cause });
}

function throwAiProviderConfigError(): never {
	throw new ORPCError("BAD_REQUEST", { message: "Invalid AI provider configuration." });
}

function throwCredentialEncryptionUnavailable(): never {
	throw new ORPCError("PRECONDITION_FAILED", {
		message: "AI providers are unavailable because ENCRYPTION_SECRET is not configured.",
	});
}

function throwResumeStructureError(error: ZodError): never {
	throw new ORPCError("BAD_REQUEST", {
		message: "Invalid resume data structure",
		cause: flattenError(error),
	});
}

View on GitHub (pinned to 3a5b12e2a4)

Solutions

  1. Check server logs for the preserved cause (AISDKError) to identify the exact upstream status.
  2. Validate the API key and model id against the provider's current API.
  3. Retry on transient 429/5xx with backoff; for 401/403 rotate the key and retest the provider.
  4. Confirm the chosen model is still available and not deprecated by the provider.

Example fix

// before
provider: { provider: 'openai', model: 'gpt-4-deprecated', apiKey: 'sk-...expired' }

// after
provider: { provider: 'openai', model: 'gpt-4o', apiKey: 'sk-...valid' }
Defensive patterns

Strategy: try-catch

Validate before calling

async function verifyProviderBeforeCall(provider) {
  const reachable = await canReachProvider(provider.baseURL, provider.apiKey);
  if (!reachable) throw new Error('provider unreachable');
}

Type guard

function isAiSdkGatewayError(e) {
  return e?.code === 'BAD_GATEWAY' && /Could not reach the AI provider/i.test(e.message);
}

Try / catch

try {
  await ai.parsePdf(input);
} catch (e) {
  if (e?.code === 'BAD_GATEWAY') {
    // inspect server logs for cause; retry with backoff for transient upstream errors
    await backoffRetry(() => ai.parsePdf(input));
  } else throw e;
}

Prevention

When it happens

Trigger: Any AI feature (parsePdf, analyze, etc.) where the underlying model call throws an instance of AISDKError — e.g. authentication error, rate limit, model not found, upstream timeout, or invalid response shape from the provider.

Common situations: Provider returns 401/403 (bad key), 429 (rate limit), 404 (wrong model id), 5xx; transient network blips; provider deprecating a model name; region restrictions on the API key.

Related errors


AI-assisted analysis of amruthpillai/reactive-resume@3a5b12e2a4 (2026-08-12). Data as JSON: /api/errors/51d31fb18236a12d. Report an issue: GitHub.