charmbracelet/crush · error

provider %s has no models configured

Error message

provider %s has no models configured

What it means

After picking the first alphabetically-sorted enabled provider, defaultModelSelection checks that the provider actually has models configured. An enabled provider with an empty Models list cannot supply a default large model, so this error is returned and wrapped by resolveSelectedModels.

Source

Thrown at internal/config/load.go:773

			MaxTokens:       defaultSmallModel.DefaultMaxTokens,
			ReasoningEffort: defaultSmallModel.DefaultReasoningEffort,
		}
		return largeModel, smallModel, err
	}

	enabledProviders := c.EnabledProviders()
	slices.SortFunc(enabledProviders, func(a, b ProviderConfig) int {
		return strings.Compare(a.ID, b.ID)
	})

	if len(enabledProviders) == 0 {
		err = fmt.Errorf("no providers configured, please configure at least one provider")
		return largeModel, smallModel, err
	}

	providerConfig := enabledProviders[0]
	if len(providerConfig.Models) == 0 {
		err = fmt.Errorf("provider %s has no models configured", providerConfig.ID)
		return largeModel, smallModel, err
	}
	defaultLargeModel := c.GetModel(providerConfig.ID, providerConfig.Models[0].ID)
	largeModel = SelectedModel{
		Provider:  providerConfig.ID,
		Model:     defaultLargeModel.ID,
		MaxTokens: defaultLargeModel.DefaultMaxTokens,
	}
	defaultSmallModel := c.GetModel(providerConfig.ID, providerConfig.Models[0].ID)
	smallModel = SelectedModel{
		Provider:  providerConfig.ID,
		Model:     defaultSmallModel.ID,
		MaxTokens: defaultSmallModel.DefaultMaxTokens,
	}
	return largeModel, smallModel, err
}

// resolvedModels holds the result of resolving user-configured model

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Add at least one model to the provider's models list in your config
  2. If the provider should use catalog models, verify the provider ID matches the catwalk catalog so its models load
  3. Remove or disable the empty provider if unused, so a healthy provider is selected first
  4. Re-run Load after fixing; note the failing provider is the first by sorted ID

Example fix

// before
"openai-custom": { "api_key": "..." }
// after
"openai-custom": { "api_key": "...", "models": [{ "id": "gpt-4o" }] }
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range cfg.EnabledProviders() {
  if len(p.Models) == 0 {
    fmt.Printf("provider %s is enabled but has no models\n", p.ID)
  }
}

Try / catch

if _, _, err := config.Load(ctx, ...); err != nil {
  var wrapped interface{ Unwrap() error }
  if errors.As(err, new(error)) && strings.Contains(err.Error(), "has no models configured") {
    // disable the empty provider or add models, then retry
  }
}

Prevention

When it happens

Trigger: Load runs, EnabledProviders() is non-empty, but enabledProviders[0] (lowest provider ID) has zero entries in its Models slice — e.g. a provider declared with credentials but no models block and no catalog models.

Common situations: Custom/self-hosted provider defined in crushrc with an API key but no models listed; provider catalog lookup failed silently for a custom provider; models list emptied by a bad config merge.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/b5c1b439d1d7c656. Report an issue: GitHub.