{"record":{"id":"69935961f067b734","repo":"charmbracelet/crush","slug":"failed-to-read-file-w-699359","errorCode":null,"errorMessage":"failed to read file: %w","messagePattern":"failed to read file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/provider.go","lineNumber":74,"sourceCode":"\n// UpdateProviders updates the Catwalk providers list from a specified source.\nfunc UpdateProviders(pathOrURL string) error {\n\tvar providers []catwalk.Provider\n\tpathOrURL = cmp.Or(pathOrURL, os.Getenv(\"CATWALK_URL\"), defaultCatwalkURL)\n\n\tswitch {\n\tcase pathOrURL == \"embedded\":\n\t\tproviders = embedded.GetAll()\n\tcase strings.HasPrefix(pathOrURL, \"http://\") || strings.HasPrefix(pathOrURL, \"https://\"):\n\t\tvar err error\n\t\tproviders, err = catwalk.NewWithURL(pathOrURL).GetProviders(context.Background(), \"\")\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to fetch providers from Catwalk: %w\", err)\n\t\t}\n\tdefault:\n\t\tcontent, err := os.ReadFile(pathOrURL)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to read file: %w\", err)\n\t\t}\n\t\tif err := json.Unmarshal(content, &providers); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to unmarshal provider data: %w\", err)\n\t\t}\n\t\tif len(providers) == 0 {\n\t\t\treturn fmt.Errorf(\"no providers found in the provided source\")\n\t\t}\n\t}\n\n\tif err := newCache[[]catwalk.Provider](cachePathFor(\"providers\")).Store(providers); err != nil {\n\t\treturn fmt.Errorf(\"failed to save providers to cache: %w\", err)\n\t}\n\n\tslog.Info(\"Providers updated successfully\", \"count\", len(providers), \"from\", pathOrURL, \"to\", cachePathFor)\n\treturn nil\n}\n\n// resolveHyperAPIKey returns the Hyper API key from the environment or","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/provider.go#L56-L92","documentation":"When UpdateProviders' pathOrURL is neither \"embedded\" nor an http(s) URL, it is treated as a filesystem path and read with os.ReadFile. This error wraps the read failure (file not found, permission denied, is-a-directory). It indicates the local provider JSON source could not be opened.","triggerScenarios":"Calling config.UpdateProviders with a local path (e.g. \"providers.json\", \"~/catwalk.json\") that does not exist, has wrong permissions, is a directory, or contains an unexpanded `~` which Go does not expand.","commonSituations":"Typo in the path; running from a different working directory with a relative path; forgetting that `~` is not shell-expanded before reaching os.ReadFile; file created by another user with 0600 perms.","solutions":["Verify the path exists: `ls -l <path>` and fix typos or pass an absolute path.","Expand `~` yourself before calling (os.UserHomeDir or filepath.Join).","Fix permissions with chmod/chown so the process user can read the file.","If it should be remote, prefix the URL with http:// or https:// so it is not treated as a file path."],"exampleFix":"// before\nerr := config.UpdateProviders(\"~/providers.json\")\n// after\nhome, _ := os.UserHomeDir()\nerr := config.UpdateProviders(filepath.Join(home, \"providers.json\"))","handlingStrategy":"validation","validationCode":"path := src\nif strings.HasPrefix(path, \"~\") {\n    home, _ := os.UserHomeDir()\n    path = filepath.Join(home, path[1:])\n}\nif fi, err := os.Stat(path); err != nil {\n    return fmt.Errorf(\"provider source not accessible: %w\", err)\n} else if fi.IsDir() {\n    return fmt.Errorf(\"provider source is a directory: %s\", path)\n}","typeGuard":null,"tryCatchPattern":"if _, err := os.Stat(path); err != nil {\n    if errors.Is(err, os.ErrNotExist) {\n        slog.Error(\"provider file missing\", \"path\", path)\n    } else if errors.Is(err, os.ErrPermission) {\n        slog.Error(\"provider file unreadable\", \"path\", path)\n    }\n    return err\n}","preventionTips":["Use absolute paths in config, never bare `~`.","Verify the file exists from the same working directory the app runs in.","Keep provider JSON files 0o644 and owned by the running user.","Check for http(s) prefix confusion: file paths must not start with http."],"tags":["filesystem","file-not-found","providers","config"],"backgroundTag":"file-not-found","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}