musistudio/claude-code-router · error · Error

No available models. Configure at least one provider with a

Error message

No available models. Configure at least one provider with a model before starting CCR Gateway or opening an agent through CCR.

What it means

assertAvailableGatewayModels throws NO_AVAILABLE_GATEWAY_MODELS_MESSAGE when availableGatewayModelIds(config) returns an empty list — i.e. no configured provider exposes at least one model and no virtual model profile supplies one. It guards gateway startup and agent open paths so users fail fast instead of getting a gateway with zero routable models.

Source

Thrown at packages/core/src/contracts/app.ts:1121

  displayName: string;
  enabled: boolean;
  execution: VirtualModelExecutionConfig;
  id: string;
  instructions?: VirtualModelInstructionsConfig;
  key: string;
  match: VirtualModelMatchConfig;
  materialization: VirtualModelMaterializationConfig;
  metadata?: Record<string, unknown>;
  toolChoice?: unknown;
  tools: VirtualModelToolConfig[];
};

export const NO_AVAILABLE_GATEWAY_MODELS_MESSAGE =
  "No available models. Configure at least one provider with a model before starting CCR Gateway or opening an agent through CCR.";

export function assertAvailableGatewayModels(config: Pick<AppConfig, "Providers" | "virtualModelProfiles">): void {
  if (!hasAvailableGatewayModels(config)) {
    throw new Error(NO_AVAILABLE_GATEWAY_MODELS_MESSAGE);
  }
}

export function hasAvailableGatewayModels(config: Pick<AppConfig, "Providers" | "virtualModelProfiles">): boolean {
  return availableGatewayModelIds(config).length > 0;
}

export function availableGatewayModelIds(config: Pick<AppConfig, "Providers" | "virtualModelProfiles">): string[] {
  const baseEntries = availableGatewayBaseModelEntries(config.Providers);
  const ids = baseEntries.map((entry) => `${entry.providerName}/${entry.modelName}`);

  for (const profile of config.virtualModelProfiles ?? []) {
    if (!isGatewayModelVisibleVirtualProfile(profile)) {
      continue;
    }

    for (const entry of baseEntries) {
      for (const prefix of profile.match?.prefixes ?? []) {

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Add at least one model to a configured provider (e.g. set models: ["gpt-4o"] or the provider's equivalent) in the Providers config
  2. Alternatively define a virtualModelProfiles entry that maps an available model
  3. Verify provider config was loaded (check the config file the app actually reads) and that provider is enabled
  4. Use hasAvailableGatewayModels(config) in UI flows to disable gateway start instead of throwing

Example fix

// before
assertAvailableGatewayModels(config); // throws
// after
config.Providers[0].models = ["claude-sonnet-4"];
assertAvailableGatewayModels(config);
Defensive patterns

Strategy: validation

Validate before calling

if (!hasAvailableGatewayModels(config)) { /* prompt user to add a provider+model instead of starting */ }

Type guard

import { hasAvailableGatewayModels } from "@scope/core/contracts/app";
const canStart = (c: AppConfig) => hasAvailableGatewayModels(c);

Prevention

When it happens

Trigger: Calling assertAvailableGatewayModels with an AppConfig whose Providers all have empty model lists (or no Providers at all) and no virtualModelProfiles with models; typically invoked before starting CCR Gateway or opening an agent.

Common situations: Fresh install with no provider configured; provider entries created but models array left empty; importing a config that dropped model definitions; all providers disabled/removed while profiles remain.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/1a056d3c89efe164. Report an issue: GitHub.