infiniflow/ragflow · error · Error

Failed to download ${file.path}: ${response.status} ${respon

Error message

Failed to download ${file.path}: ${response.status} ${response.statusText}

What it means

Raised when the raw file download (raw.githubusercontent.com or gitee.com/.../raw/...) returns a non-ok HTTP status. Includes the status code and statusText for diagnosis. Common causes: the file was removed between listing and download, the ref moved, the URL requires authentication (private repo), or rate limiting on the raw endpoint.

Source

Thrown at web/src/pages/skills/components/upload-modal.tsx:514

      // If download_url is not provided, construct raw URL
      if (!downloadUrl) {
        if (platform === 'github') {
          // https://raw.githubusercontent.com/owner/repo/ref/path
          downloadUrl = `${config.rawBase}/${owner}/${repo}/${ref}/${file.path}`;
        } else if (platform === 'gitee') {
          // https://gitee.com/owner/repo/raw/ref/path
          downloadUrl = `${config.rawBase}/${owner}/${repo}/raw/${ref}/${file.path}`;
        }
      }

      if (!downloadUrl) {
        throw new Error(`Download URL not available for file: ${file.path}`);
      }

      const response = await fetch(downloadUrl);
      if (!response.ok) {
        throw new Error(
          `Failed to download ${file.path}: ${response.status} ${response.statusText}`,
        );
      }

      const blob = await response.blob();
      const fileName = file.path.split('/').pop() || 'file';

      // Use MIME type from extension if blob.type is empty or generic
      let fileType = blob.type;
      if (
        !fileType ||
        fileType === 'application/octet-stream' ||
        fileType === 'text/plain'
      ) {
        fileType = getMimeTypeFromExtension(file.path);
      }

      const downloadedFile = new File([blob], fileName, {

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Retry the import — transient 403/429 from raw endpoints often clear
  2. For private repos, fetch content via the API's download_url (which includes a signed token) or the contents API base64 payload instead of constructing raw URLs
  3. Verify the file still exists at the given ref in the browser
  4. Check the status code in the message: 404 = file gone, 403 = auth/rate, 5xx = upstream issue

Example fix

// before
const response = await fetch(downloadUrl);
if (!response.ok) {
  throw new Error(`Failed to download ${file.path}: ${response.status} ${response.statusText}`);
}

// after
const response = await fetch(downloadUrl, token ? { headers: { Authorization: `Bearer ${token}` } } : undefined);
if (!response.ok) {
  throw new Error(`Failed to download ${file.path}: ${response.status} ${response.statusText}`);
}
Defensive patterns

Strategy: retry

Validate before calling

// pre-flight: HEAD the raw URL to confirm it resolves
const probe = await fetch(downloadUrl, { method: 'HEAD' });
if (!probe.ok) {
  skipOrWarn(`File unreachable (${probe.status}): ${file.path}`);
}

Type guard

function isTransientHttpError(status: number): boolean {
  return status === 429 || status >= 500;
}

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  const res = await fetch(downloadUrl);
  if (res.ok) { /* use blob */ break; }
  if (!isTransientHttpError(res.status)) {
    throw new Error(`Failed to download ${file.path}: ${res.status} ${res.statusText}`);
  }
  await new Promise((r) => setTimeout(r, 2 ** attempt * 500)); // backoff, then retry
}

Prevention

When it happens

Trigger: fetch(downloadUrl) for a listed file returns 404 (file deleted/renamed since the listing), 401/403 (private repo, raw URL needs token which is not attached to raw fetches), or 429 rate limit.

Common situations: Repo actively changing during import; private repository imported with a token that authenticates the API but not the raw fetch; large repos hitting raw CDN limits.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/e7d4d04b2ff42534. Report an issue: GitHub.