chatboxai/chatbox · error · GitHubApiError

Failed to fetch file: ${filePath}

Error message

Failed to fetch file: ${filePath}

What it means

Thrown by fetchFileContent() when raw.githubusercontent.com returns a non-OK status for a single file. Unlike githubFetch (which special-cases 404 and 403), this raw-URL path has no status-specific branches — any failure becomes a GitHubApiError with the original status code attached. The function powers SKILL.md reads during detection and individual file downloads.

Source

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

  }

  return detected
}

export async function fetchFileContent(owner: string, repo: string, filePath: string): Promise<string> {
  // Git allows `#`/`?` in filenames — encode per segment so they don't truncate the URL
  const encodedPath = filePath.split('/').map(encodeURIComponent).join('/')
  const url = `https://raw.githubusercontent.com/${owner}/${repo}/HEAD/${encodedPath}`

  const cached = getCached<string>(url)
  if (cached !== undefined) return cached

  const response = await fetch(url, {
    headers: { 'User-Agent': USER_AGENT },
  })

  if (!response.ok) {
    throw new GitHubApiError(`Failed to fetch file: ${filePath}`, response.status)
  }

  const content = await response.text()
  setCache(url, content)
  return content
}

export async function downloadSkillFiles(
  owner: string,
  repo: string,
  skillPath: string,
  targetDir: string
): Promise<void> {
  try {
    const downloaded = await downloadSkillFilesViaTree(owner, repo, skillPath, targetDir)
    if (downloaded) return
  } catch (error) {
    if (error instanceof GitHubApiError && (error.statusCode === 403 || error.statusCode === 429)) {

View on GitHub (pinned to 81571269ad)

Solutions

  1. Verify the file exists at the repo's default branch by opening the raw URL in a browser.
  2. If the repo is private, supply authentication — raw URLs need a token in the URL or use the contents API with an Authorization header.
  3. Retry once after a short delay for transient CDN 5xx; clearCache() is not needed since this URL was never cached on failure.
  4. For LFS files, fetch via the contents/blobs API instead of raw.

Example fix

// before
if (!response.ok) {
  throw new GitHubApiError(`Failed to fetch file: ${filePath}`, response.status)
}

// after — surface the status so callers can distinguish 404 (gone) from 5xx (retry)
if (!response.ok) {
  throw new GitHubApiError(
    `Failed to fetch file: ${filePath} (HTTP ${response.status} ${response.statusText})`,
    response.status
  )
}
Defensive patterns

Strategy: retry

Validate before calling

// Validate the file path shape before fetching.
function isValidFilePath(p: string): boolean {
  return typeof p === 'string' && p.length > 0 && p.length < 4096 && !p.includes('\\')
}
if (!isValidFilePath(filePath)) throw new Error('Invalid file path')

Type guard

function isGitHubApiError(e: unknown): e is { statusCode: number; message: string } {
  return e instanceof Error && typeof (e as any).statusCode === 'number'
}

Try / catch

try {
  return await fetchFileContent(owner, repo, filePath)
} catch (error) {
  if (isGitHubApiError(error) && (error.statusCode === 404)) return null // file gone
  if (isGitHubApiError(error) && error.statusCode >= 500) {
    return await backoffRetry(() => fetchFileContent(owner, repo, filePath))
  }
  throw error
}

Prevention

When it happens

Trigger: Requesting raw.githubusercontent.com/{owner}/{repo}/HEAD/{encodedPath} where the path does not exist at HEAD (404), the repo is private (404), the file is git-LFS tracked (pointer served, or 404 on media), or raw CDN returns 5xx. Also triggered when filePath contains characters that encodeURIComponent mishandles for the raw endpoint.

Common situations: A SKILL.md listed in the tree was deleted before the content fetch (HEAD advanced); private repo accessed without a token; LFS-backed file; transient raw CDN error. The per-segment encodeURIComponent handles # and ? in filenames, but a leading slash or unusual encoding can still produce a 404.

Related errors


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