charmbracelet/crush · error

default providers are disabled and there are no custom provi

Error message

default providers are disabled and there are no custom providers are configured

What it means

configureProviders explicitly rejects a configuration where default (catalog) providers are disabled but zero custom providers were defined — the app would have no way to talk to any LLM. The error is returned verbatim without wrapping the cause.

Source

Thrown at internal/config/load.go:514

		// Custom-provider headers share the MCP error contract; see
		// the known-provider loop above.
		for k, v := range providerConfig.ExtraHeaders {
			resolved, err := resolver.ResolveValue(v)
			if err != nil {
				return fmt.Errorf("resolving provider %s header %q: %w", id, k, err)
			}
			if resolved == "" {
				delete(providerConfig.ExtraHeaders, k)
				continue
			}
			providerConfig.ExtraHeaders[k] = resolved
		}

		c.Providers.Set(id, providerConfig)
	}

	if c.Providers.Len() == 0 && c.Options.DisableDefaultProviders {
		return fmt.Errorf("default providers are disabled and there are no custom providers are configured")
	}

	return nil
}

// applyEnv sets top-level env vars from the config. Keys are sorted for
// deterministic ordering so that vars referencing other vars via the
// value resolver produce consistent results.
func (c *Config) applyEnv(resolver VariableResolver) {
	keys := make([]string, 0, len(c.Env))
	for k := range c.Env {
		keys = append(keys, k)
	}
	slices.Sort(keys)
	for _, k := range keys {
		resolved, err := resolver.ResolveValue(c.Env[k])
		if err != nil {
			slog.Warn("Skipping env var due to resolution failure.", "key", k, "value", c.Env[k], "error", err)

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Add at least one custom provider under the providers section
  2. Or remove/disable the disable_default_providers option to use catalog providers
  3. Verify the providers section wasn't lost in a merge or placed in the wrong scope/file
  4. Check that provider IDs don't collide/overwrite each other leaving the map empty

Example fix

// before (crush.json)
{"options": {"disable_default_providers": true}}
// after
{"options": {"disable_default_providers": true}, "providers": {"myllm": {"base_url": "http://localhost:8080/v1", "api_key": "x"}}}
Defensive patterns

Strategy: validation

Validate before calling

raw, _ := os.ReadFile("crush.json")
var c struct {
    Options  struct{ DisableDefaultProviders bool `json:"disable_default_providers"` } `json:"options"`
    Providers map[string]json.RawMessage `json:"providers"`
}
_ = json.Unmarshal(raw, &c)
if c.Options.DisableDefaultProviders && len(c.Providers) == 0 {
    return errors.New("disable_default_providers requires at least one custom provider")
}

Try / catch

store, err := config.Load(ctx, opts)
if err != nil {
    if strings.Contains(err.Error(), "default providers are disabled") {
        return errors.New("add a custom provider or re-enable default providers")
    }
    return err
}

Prevention

When it happens

Trigger: c.Providers.Len() == 0 && c.Options.DisableDefaultProviders is true at the end of configureProviders — i.e. options.disable_default_providers is set (true) while the providers map is empty.

Common situations: User set disable_default_providers: true intending to use only custom providers but forgot to define one; a merge dropped the custom providers section; copying a minimal config snippet that disables defaults.

Related errors


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