{"record":{"id":"63c6495e67d5cd0f","repo":"charmbracelet/crush","slug":"no-variable-resolver-configured","errorCode":null,"errorMessage":"no variable resolver configured","messagePattern":"no variable resolver configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/store.go","lineNumber":172,"sourceCode":"// WorkingDir returns the current working directory.\nfunc (s *ConfigStore) WorkingDir() string {\n\treturn s.workingDir\n}\n\n// Resolver returns the variable resolver.\nfunc (s *ConfigStore) Resolver() VariableResolver {\n\ts.writeMu.RLock()\n\tdefer s.writeMu.RUnlock()\n\treturn s.resolver\n}\n\n// Resolve resolves a variable reference using the configured resolver.\nfunc (s *ConfigStore) Resolve(key string) (string, error) {\n\ts.writeMu.RLock()\n\tr := s.resolver\n\ts.writeMu.RUnlock()\n\tif r == nil {\n\t\treturn \"\", fmt.Errorf(\"no variable resolver configured\")\n\t}\n\treturn r.ResolveValue(key)\n}\n\n// KnownProviders returns the list of known providers.\nfunc (s *ConfigStore) KnownProviders() []catwalk.Provider {\n\ts.writeMu.RLock()\n\tdefer s.writeMu.RUnlock()\n\treturn s.knownProviders\n}\n\n// RefetchHyperProvider re-fetches the Hyper provider catalog from the\n// remote API and updates the in-memory known providers list and config.\n// This is called after OAuth authentication completes so the latest\n// models are available without restarting.\nfunc (s *ConfigStore) RefetchHyperProvider(ctx context.Context) error {\n\t// Build a fresh client that reads the API key from the live config,\n\t// not the stale snapshot captured at startup. The syncer's original","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/store.go#L154-L190","documentation":"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.","triggerScenarios":"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.","commonSituations":"Using ConfigStore programmatically without wiring shellVariableResolver; test fixtures omitting the resolver; initialization order bug where Resolve runs before the resolver is attached.","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."],"exampleFix":"// before\nstore := config.NewConfigStore(...) // no resolver\nstore.Resolve(\"API_KEY\") // error\n// after\nstore := config.NewConfigStore(...)\nstore.SetResolver(shellVariableResolver)\nstore.Resolve(\"API_KEY\")","handlingStrategy":"try-catch","validationCode":"if store == nil || store.Resolver() == nil {\n    return errors.New(\"config store not fully initialized\")\n}","typeGuard":null,"tryCatchPattern":"val, err := store.Resolve(key)\nif err != nil && strings.Contains(err.Error(), \"no variable resolver configured\") {\n    return fmt.Errorf(\"cannot expand %q: resolver missing; check store initialization\", key)\n}","preventionTips":["Always configure a resolver when constructing ConfigStore","Fail fast at startup if resolver wiring is skipped","Install a stub resolver in test fixtures"],"tags":["config","initialization","resolver"],"backgroundTag":"dependency-not-initialized","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}