chenhg5/cc-connect · error

fetch skill presets: %w

Error message

fetch skill presets: %w

What it means

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.

Source

Thrown at core/skill_presets.go:110

		return c.data, nil
	}

	primaryURL := c.url
	if primaryURL == "" {
		primaryURL = defaultSkillPresetsURL
	}

	result, err := fetchSkillPresetsFromURL(primaryURL, skillPresetsHTTPTimeout)
	if err != nil {
		slog.Warn("primary skill presets fetch failed, trying fallback", "url", primaryURL, "error", err)
		result, err = fetchSkillPresetsFromURL(fallbackSkillPresetsURL, skillPresetsFallbackHTTPTimeout)
	}
	if err != nil {
		if c.data != nil {
			slog.Warn("all skill presets sources failed, using stale cache", "error", err)
			return c.data, nil
		}
		return nil, fmt.Errorf("fetch skill presets: %w", err)
	}

	c.data = result
	c.fetchedAt = time.Now()
	return c.data, nil
}

func fetchSkillPresetsFromURL(url string, timeout time.Duration) (*SkillPresetsResponse, error) {
	slog.Debug("fetching skill presets", "url", url)
	client := &http.Client{Timeout: timeout}
	resp, err := client.Get(url)
	if err != nil {
		return nil, fmt.Errorf("HTTP GET %s: %w", url, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("HTTP GET %s: status %d", url, resp.StatusCode)

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Restore network access (or proxy config) and retry the fetch
  2. Pre-seed the presets cache so a stale copy exists for offline fallback
  3. Check the wrapped error (%w) to see which source URL failed and why; fix or remove dead sources from the config
  4. Add the failing hosts to an allowlist if a firewall is blocking them

Example fix

// before
presets, err := fetchPresets(ctx)
// after
presets, err := fetchPresets(ctx)
if err != nil {
    slog.Warn("skill presets unavailable, continuing with empty list", "err", err)
    presets = &SkillPresetsResponse{}
}
Defensive patterns

Strategy: fallback

Validate before calling

// before fetching, check a cached copy exists to fall back on
if cache := readPresetsCache(); cache != nil {
    slog.Info("skill presets: using cached copy", "fetched_at", cacheTime)
}

Type guard

func hasStaleCache(c *presetsCache) bool {
    c.mu.Lock(); defer c.mu.Unlock()
    return c.data != nil
}

Try / catch

presets, err := fetchPresets(ctx)
if err != nil {
    var netErr net.Error
    if errors.As(err, &netErr) || strings.Contains(err.Error(), "fetch skill presets") {
        slog.Warn("skill presets unavailable offline; using empty list", "err", err)
        presets = &core.SkillPresetsResponse{}
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/8c8e41dc96fdde53. Report an issue: GitHub.