{"record":{"id":"8c8e41dc96fdde53","repo":"chenhg5/cc-connect","slug":"fetch-skill-presets-w","errorCode":null,"errorMessage":"fetch skill presets: %w","messagePattern":"fetch skill presets: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/skill_presets.go","lineNumber":110,"sourceCode":"\t\treturn c.data, nil\n\t}\n\n\tprimaryURL := c.url\n\tif primaryURL == \"\" {\n\t\tprimaryURL = defaultSkillPresetsURL\n\t}\n\n\tresult, err := fetchSkillPresetsFromURL(primaryURL, skillPresetsHTTPTimeout)\n\tif err != nil {\n\t\tslog.Warn(\"primary skill presets fetch failed, trying fallback\", \"url\", primaryURL, \"error\", err)\n\t\tresult, err = fetchSkillPresetsFromURL(fallbackSkillPresetsURL, skillPresetsFallbackHTTPTimeout)\n\t}\n\tif err != nil {\n\t\tif c.data != nil {\n\t\t\tslog.Warn(\"all skill presets sources failed, using stale cache\", \"error\", err)\n\t\t\treturn c.data, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"fetch skill presets: %w\", err)\n\t}\n\n\tc.data = result\n\tc.fetchedAt = time.Now()\n\treturn c.data, nil\n}\n\nfunc fetchSkillPresetsFromURL(url string, timeout time.Duration) (*SkillPresetsResponse, error) {\n\tslog.Debug(\"fetching skill presets\", \"url\", url)\n\tclient := &http.Client{Timeout: timeout}\n\tresp, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"HTTP GET %s: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"HTTP GET %s: status %d\", url, resp.StatusCode)","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/skill_presets.go#L92-L128","documentation":"The skill presets fetcher aggregates multiple remote sources; fetch throws \"fetch skill presets: %w\" only when every source failed AND there is no stale cached copy to fall back on. The wrapped error is the last/aggregate source failure. When a stale cache exists the caller only logs a warning and serves old data instead.","triggerScenarios":"Calling the skill presets listing (e.g. the /skills preset UI) while offline, when all preset source URLs are unreachable, and the local cache file has never been populated (first run) or was cleared.","commonSituations":"First launch on an air-gapped/CI machine with no network; DNS failure on the host; preset CDN temporarily down shortly after a fresh install with no cache yet.","solutions":["Restore network access (or proxy config) and retry the fetch","Pre-seed the presets cache so a stale copy exists for offline fallback","Check the wrapped error (%w) to see which source URL failed and why; fix or remove dead sources from the config","Add the failing hosts to an allowlist if a firewall is blocking them"],"exampleFix":"// before\npresets, err := fetchPresets(ctx)\n// after\npresets, err := fetchPresets(ctx)\nif err != nil {\n    slog.Warn(\"skill presets unavailable, continuing with empty list\", \"err\", err)\n    presets = &SkillPresetsResponse{}\n}","handlingStrategy":"fallback","validationCode":"// before fetching, check a cached copy exists to fall back on\nif cache := readPresetsCache(); cache != nil {\n    slog.Info(\"skill presets: using cached copy\", \"fetched_at\", cacheTime)\n}","typeGuard":"func hasStaleCache(c *presetsCache) bool {\n    c.mu.Lock(); defer c.mu.Unlock()\n    return c.data != nil\n}","tryCatchPattern":"presets, err := fetchPresets(ctx)\nif err != nil {\n    var netErr net.Error\n    if errors.As(err, &netErr) || strings.Contains(err.Error(), \"fetch skill presets\") {\n        slog.Warn(\"skill presets unavailable offline; using empty list\", \"err\", err)\n        presets = &core.SkillPresetsResponse{}\n    }\n}","preventionTips":["Pre-populate the presets cache on first install so offline starts have a fallback","Configure multiple preset source URLs so one failure doesn't empty the list","Monitor the wrapped cause: repeated all-sources-failed indicates DNS/firewall issues, not flakiness"],"tags":["network","http","cache","fallback"],"backgroundTag":"network-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}