{"record":{"id":"34c728f8a970b156","repo":"charmbracelet/crush","slug":"failed-to-unmarshal-provider-data-w","errorCode":null,"errorMessage":"failed to unmarshal provider data: %w","messagePattern":"failed to unmarshal provider data: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/config/provider.go","lineNumber":77,"sourceCode":"\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\n// the raw config value. The env var takes precedence.\nfunc resolveHyperAPIKey(cfg *Config) string {\n\tif key := os.Getenv(\"HYPER_API_KEY\"); key != \"\" {","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/config/provider.go#L59-L95","documentation":"After successfully reading a local provider file, UpdateProviders unmarshals it with encoding/json into []catwalk.Provider. This error wraps the json.Unmarshal failure: the file is not valid JSON or its shape does not match []catwalk.Provider (e.g. an object instead of an array, wrong field types).","triggerScenarios":"Calling config.UpdateProviders with a file path to content that is not a JSON array of providers: truncated JSON, JSONL, a single provider object, comments in JSON, or wrong field types (numbers where strings expected).","commonSituations":"Exporting a single provider instead of an array; hand-editing JSON and leaving a trailing comma; BOM or comments at the top of the file; schema drift after a catwalk.Provider field type change.","solutions":["Validate the file: `jq . providers.json` to find the syntax error.","Ensure the top level is a JSON array `[ {...provider...} ]`, not an object.","Match catwalk.Provider field names/types exactly (snake_case JSON tags).","Regenerate the file from a known-good source (embedded catalog or catwalk URL)."],"exampleFix":"// before (providers.json)\n{\"id\": \"openai\", \"name\": \"OpenAI\"}\n// after\n[{\"id\": \"openai\", \"name\": \"OpenAI\"}]","handlingStrategy":"validation","validationCode":"var probe []catwalk.Provider\ncontent, err := os.ReadFile(path)\nif err != nil { return err }\nif err := json.Unmarshal(content, &probe); err != nil {\n    return fmt.Errorf(\"provider file is not valid JSON for []catwalk.Provider: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"var synErr *json.SyntaxError\nif err := json.Unmarshal(content, &providers); err != nil {\n    if errors.As(err, &synErr) {\n        slog.Error(\"bad JSON\", \"offset\", synErr.Offset, \"msg\", synErr.Error())\n    }\n    return err\n}","preventionTips":["Run `jq . file.json` as a pre-commit check on provider files.","Export arrays of providers, never a single object, for UpdateProviders.","Strip BOM and comments; encoding/json accepts neither.","Pin the file format to catwalk.Provider's snake_case JSON schema."],"tags":["json","unmarshal","providers","validation"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}