charmbracelet/crush · error
default providers are disabled and there are no custom…
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.
Solutions
- Add at least one custom provider under the providers section
- Or remove/disable the disable_default_providers option to use catalog providers
- Verify the providers section wasn't lost in a merge or placed in the wrong scope/file
- 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
- Only set disable_default_providers when a custom provider is fully defined
- Verify the providers section exists and is non-empty after merges
- Keep disable flag and custom providers in the same file to keep them in sync
- Lint config for this invariant in CI
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
- no providers found in the provided source
- failed to configure providers
- failed to configure selected models
- failed to create request for provider
- failed to initialize config
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/be851d3560cd0a52.
Report an issue: GitHub.
Appendix: 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)