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 test handler's catch-all when aiProvidersService.test rejects with an error that is neither the 'INVALID_AI_BASE_URL' sentinel nor an ORPCError. It represents any upstream/AI-provider-side failure during the connectivity test (network, auth, 5xx, malformed response). The original cause is not attached, so only the generic message surfaces.

Solutions

  1. Open the provider's dashboard and confirm the API key is valid and has quota.
  2. Re-enter and re-save the API key, then re-test to force a fresh credential.
  3. Verify the baseURL is correct and reachable from the server (curl from the host).
  4. Check provider status pages and server outbound network/egress rules.
  5. Inspect server logs for the original (un-remapped) error cause to pinpoint auth vs network vs 5xx.

Example fix

// before
// provider saved with old key
{ provider: 'openai', baseURL: 'https://api.openai.com/v1', apiKey: 'sk-...revoked' }

// after
// rotate key, save, then re-test
{ provider: 'openai', baseURL: 'https://api.openai.com/v1', apiKey: 'sk-...valid' }
Defensive patterns

Strategy: retry

Validate before calling

async function canReachProvider(baseURL, apiKey) {
  try {
    const res = await fetch(baseURL + '/models', { headers: { Authorization: `Bearer ${apiKey}` } });
    return res.ok || res.status === 401; // 401 means reachable, just auth
  } catch { return false; }
}

Type guard

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

Try / catch

try {
  await testProvider({ id });
} catch (e) {
  if (e?.code === 'BAD_GATEWAY') {
    showToast('Cannot reach the provider. Check the key, baseURL, and network.');
  } else throw e;
}

Prevention

When it happens

Trigger: POST /ai-providers/{id}/test where the saved provider's endpoint is unreachable, returns a non-2xx (auth failure, quota, 5xx), times out, or the AI SDK throws a non-sentinel error. Anything not remapped to INVALID base URL or rethrown as ORPCError lands here.

Common situations: Expired or revoked API key stored against the provider; wrong baseURL after a provider migration; firewall/proxy blocking outbound HTTPS; provider rate-limiting or outage; DNS failure for the provider host.

Related errors


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

Appendix: source

Thrown at packages/api/src/features/ai-providers/router.ts:140

			summary: "Test saved AI provider",
			description: "Decrypts the saved API key server-side and validates the provider/model connection.",
		})
		.input(z.object({ id: z.string() }))
		.output(type<AiProviderResponse>())
		.use(aiRequestRateLimit)
		.errors({
			BAD_REQUEST: { message: "Invalid AI provider configuration.", status: 400 },
			BAD_GATEWAY: { message: "The AI provider returned an error or is unreachable.", status: 502 },
			NOT_FOUND: { message: "AI provider was not found.", status: 404 },
			PRECONDITION_FAILED: { message: "AI agent workspace is not configured.", status: 412 },
		})
		.handler(async ({ context, input }) => {
			try {
				return await aiProvidersService.test({ id: input.id, userId: context.user.id });
			} catch (error) {
				if (isInvalidAiBaseUrl(error)) throwInvalidProviderConfig();
				if (error instanceof ORPCError) throw error;
				throw new ORPCError("BAD_GATEWAY", { message: "Could not reach the AI provider." });
			}
		}),
};

View on GitHub (pinned to 3a5b12e2a4)