charmbracelet/crush · error
no variable resolver configured
Error message
no variable resolver configured
What it means
Thrown by ConfigStore.Resolve when no variable resolver has been configured on the store. The Resolve method only reads s.resolver under a read lock; if it is nil, there is no way to expand the variable reference, so it returns this error instead of panicking.
Source
Thrown at internal/config/store.go:172
// WorkingDir returns the current working directory.
func (s *ConfigStore) WorkingDir() string {
return s.workingDir
}
// Resolver returns the variable resolver.
func (s *ConfigStore) Resolver() VariableResolver {
s.writeMu.RLock()
defer s.writeMu.RUnlock()
return s.resolver
}
// Resolve resolves a variable reference using the configured resolver.
func (s *ConfigStore) Resolve(key string) (string, error) {
s.writeMu.RLock()
r := s.resolver
s.writeMu.RUnlock()
if r == nil {
return "", fmt.Errorf("no variable resolver configured")
}
return r.ResolveValue(key)
}
// KnownProviders returns the list of known providers.
func (s *ConfigStore) KnownProviders() []catwalk.Provider {
s.writeMu.RLock()
defer s.writeMu.RUnlock()
return s.knownProviders
}
// RefetchHyperProvider re-fetches the Hyper provider catalog from the
// remote API and updates the in-memory known providers list and config.
// This is called after OAuth authentication completes so the latest
// models are available without restarting.
func (s *ConfigStore) RefetchHyperProvider(ctx context.Context) error {
// Build a fresh client that reads the API key from the live config,
// not the stale snapshot captured at startup. The syncer's originalView on GitHub (pinned to 7944b8e522)
Solutions
- Construct the ConfigStore with a resolver configured (the shell variable resolver used in production wiring).
- Check for init-order bugs where Resolve is called before the resolver is set.
- In tests, install a stub resolver so Resolve has a target.
- Guard callers: treat a nil resolver as a configuration bug and fail fast with a clear message.
Example fix
// before
store := config.NewConfigStore(...) // no resolver
store.Resolve("API_KEY") // error
// after
store := config.NewConfigStore(...)
store.SetResolver(shellVariableResolver)
store.Resolve("API_KEY") Defensive patterns
Strategy: try-catch
Validate before calling
if store == nil || store.Resolver() == nil {
return errors.New("config store not fully initialized")
} Try / catch
val, err := store.Resolve(key)
if err != nil && strings.Contains(err.Error(), "no variable resolver configured") {
return fmt.Errorf("cannot expand %q: resolver missing; check store initialization", key)
} Prevention
- Always configure a resolver when constructing ConfigStore
- Fail fast at startup if resolver wiring is skipped
- Install a stub resolver in test fixtures
When it happens
Trigger: Calling ConfigStore.Resolve(key) (e.g. via buildProvider or refreshApiKeyTemplate) on a store built without a resolver — a store constructed with the zero value or without the resolver option, often in tests or partial setups.
Common situations: Using ConfigStore programmatically without wiring shellVariableResolver; test fixtures omitting the resolver; initialization order bug where Resolve runs before the resolver is attached.
Related errors
- failed to initialize config: %w
- failed to initialize agent: %w
- config not loaded
- task agent not configured
- small model provider not configured
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/63c6495e67d5cd0f.
Report an issue: GitHub.