chatboxai/chatbox · error · SkillContentUnavailableError

Found ${limitedPaths.length} skill(s) in ${owner}/${repo} bu

Error message

Found ${limitedPaths.length} skill(s) in ${owner}/${repo} but failed to fetch their contents

What it means

Thrown by detectSkillsViaTree() when the repo tree listing found one or more SKILL.md paths but EVERY one of them failed to download. Partial failures (some skills fetched) are tolerated and the successfully-detected skills are returned; only total failure raises this SkillContentUnavailableError. It signals that the repo structure is discoverable but its contents are unreachable, which usually points to transient raw.githubusercontent failures or a mismatch between the tree SHA and HEAD.

Source

Thrown at src/main/skills/github-fetcher.ts:201

        try {
          const content = await fetchFileContent(owner, repo, skillMdPath)
          return {
            name: extractSkillName(content) || skillPath.split('/').pop() || repo,
            path: skillPath,
            description: extractSkillDescription(content),
          }
        } catch (error) {
          log.warn(`Failed to fetch ${skillMdPath} from ${owner}/${repo}`, error)
          fetchFailures++
          return null
        }
      })
    )
    detected.push(...batch.filter((skill): skill is DetectedSkill => skill !== null))
  }

  if (limitedPaths.length > 0 && fetchFailures === limitedPaths.length) {
    throw new SkillContentUnavailableError(
      `Found ${limitedPaths.length} skill(s) in ${owner}/${repo} but failed to fetch their contents`
    )
  }
  return detected
}

// Strategy 1: root SKILL.md | 2: skills/{name}/SKILL.md | 3: {dir}/skills/{name}/SKILL.md (fallback)
async function detectSkillsViaContents(owner: string, repo: string): Promise<DetectedSkill[]> {
  const detected: DetectedSkill[] = []

  try {
    const rootContents = await fetchRepoContents(owner, repo)
    const rootSkillMd = rootContents.find((item) => item.name === 'SKILL.md' && item.type === 'file')
    if (rootSkillMd) {
      const content = await fetchFileContent(owner, repo, 'SKILL.md')
      const name = extractSkillName(content)
      detected.push({
        name: name || repo,

View on GitHub (pinned to 81571269ad)

Solutions

  1. Retry the scan — clearCache() first to drop any stale tree entry, then re-run skills:scan-repo.
  2. If the repo uses Git LFS, fetch SKILL.md via the contents API or the LFS media endpoint instead of raw.githubusercontent.com.
  3. Confirm raw.githubusercontent.com is reachable from the user's network (some corporate proxies block it).
  4. Fall back to the contents-API strategy (detectSkillsViaContents), which the caller already does when this strategy returns null.

Example fix

// before
if (limitedPaths.length > 0 && fetchFailures === limitedPaths.length) {
  throw new SkillContentUnavailableError(
    `Found ${limitedPaths.length} skill(s) in ${owner}/${repo} but failed to fetch their contents`
  )
}

// after — treat total failure as null so the caller falls through to the contents strategy
if (limitedPaths.length > 0 && fetchFailures === limitedPaths.length) {
  log.warn(`All ${limitedPaths.length} skill fetches failed for ${owner}/${repo}; returning null for fallback`)
  return null
}
Defensive patterns

Strategy: fallback

Type guard

function isSkillContentUnavailableError(e: unknown): boolean {
  return e instanceof Error && /failed to fetch their contents/i.test(e.message)
}

Try / catch

let skills: DetectedSkill[]
try {
  skills = await scanRepoViaTree(owner, repo)
} catch (error) {
  if (isSkillContentUnavailableError(error)) {
    // Tree strategy found paths but all contents failed — fall back to contents API.
    skills = await detectSkillsViaContents(owner, repo)
  } else {
    throw error
  }
}

Prevention

When it happens

Trigger: detectSkillsInRepo runs the tree strategy, the /git/trees/HEAD call succeeds and returns SKILL.md paths, but every raw.githubusercontent.com/{owner}/{repo}/HEAD/{path} fetch in fetchFileContent returns non-OK. Happens when HEAD moved between the tree fetch and the content fetch (race), when raw CDN is flaky, or when all SKILL.md files live behind LFS or are git-ignored at the raw endpoint.

Common situations: Repo uses Git LFS for SKILL.md (raw URL serves an LFS pointer, not 200); a brief raw.githubusercontent.com outage coincides with the batched fetch window; the repo was force-pushed between the tree and content calls so HEAD no longer matches the cached tree SHA.

Related errors


AI-assisted analysis of chatboxai/chatbox@81571269ad (2026-08-12). Data as JSON: /api/errors/bdc1372e82933ea6. Report an issue: GitHub.