amruthpillai/reactive-resume · error · ORPCError

BAD_REQUEST

BAD_REQUEST

Error message

Invalid AI provider configuration.

What it means

Generic BAD_REQUEST thrown by the throwInvalidProviderConfig helper in the ai-providers router. It is reached when an underlying service call rejects with an Error whose message is exactly 'INVALID_AI_BASE_URL' (detected by isInvalidAiBaseUrl), meaning the supplied baseURL failed normalization/validation. The helper is shared by the create, update, and test handlers.

Source

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

import type { AiProviderResponse } from "./service";
import { ORPCError } from "@orpc/client";
import { type } from "@orpc/server";
import z from "zod";
import { protectedProcedure } from "../../context";
import { aiRequestRateLimit } from "../../middleware/rate-limit";
import { providerInput, updateProviderInput } from "./inputs";
import { aiProvidersService } from "./service";

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

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

export const aiProvidersRouter = {
	list: protectedProcedure
		.route({
			method: "GET",
			path: "/ai-providers",
			tags: ["AI Providers"],
			operationId: "listAiProviders",
			summary: "List saved AI providers",
			description: "Lists saved provider/model/API key combinations for the authenticated user. API keys are redacted.",
		})
		.output(type<AiProviderResponse[]>())
		.errors({
			PRECONDITION_FAILED: { message: "AI agent workspace is not configured.", status: 412 },
		})
		.handler(({ context }) => aiProvidersService.list({ userId: context.user.id })),

View on GitHub (pinned to 3a5b12e2a4)

Solutions

  1. Provide a fully-qualified https:// baseURL with no trailing slash and no /v1 or /chat/completions suffix unless the provider requires it.
  2. Trim and validate the baseURL with new URL() on the client before submit.
  3. Check the provider's documented API base (e.g. https://api.openai.com/v1) and match the selected provider enum.
  4. For local/self-hosted gateways, confirm the host is reachable and serves the expected OpenAI-compatible schema.

Example fix

// before
baseURL: 'openai.com/v1'

// after
baseURL: 'https://api.openai.com/v1'
Defensive patterns

Strategy: validation

Validate before calling

function validateBaseUrl(baseURL) {
  if (!baseURL) return undefined;
  const u = new URL(baseURL);
  if (u.protocol !== 'http:' && u.protocol !== 'https:') throw new Error('INVALID_AI_BASE_URL');
  return u.origin + (u.pathname.replace(/\/$/, ''));
}

Type guard

function looksLikeValidAiBaseUrl(s) {
  try { const u = new URL(s); return u.protocol === 'https:' && /^https:\/\//.test(s); } catch { return false; }
}

Try / catch

try {
  await createProvider(input);
} catch (e) {
  if (e.code === 'BAD_REQUEST' && /Invalid AI provider configuration/i.test(e.message)) {
    showFieldError('baseURL', 'Enter a full https:// URL for the provider.');
  } else throw e;
}

Prevention

When it happens

Trigger: POST/PATCH /ai-providers or POST /ai-providers/{id}/test where the baseURL field is malformed (non-URL string, wrong scheme, unreachable host during normalization) causing the service to throw the sentinel 'INVALID_AI_BASE_URL' error, which the router remaps to this message.

Common situations: User enters a baseURL without the https:// scheme, with a trailing path that the provider rejects, with a typo, or pointing to a provider-specific endpoint path that is invalid for the chosen provider kind; copy-paste errors from docs that include extra quotes or whitespace.

Related errors


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