BerriAI/litellm · error · Exception

Error fetching file

Error message

Error fetching file '{file_path}': {e}

What it means

get_file_content wraps any exception that has no HTTP response attached — i.e., a transport-level failure: DNS resolution failure, connection refused/reset, TLS certificate verification error, proxy failures, or an unexpected decoding bug. The original exception text is appended verbatim, which distinguishes it from the HTTP-status variants (293-295).

Solutions

  1. Verify basic reachability: curl https://api.bitbucket.org/2.0 from the same container/host
  2. Configure the proxy via HTTPS_PROXY/HTTP_PROXY (and NO_PROXY for internal hosts) in the process env
  3. For TLS interception, trust the CA bundle: mount the corp CA and set SSL_CERT_FILE / REQUESTS_CA_BUNDLE for the httpx handler
  4. Pin a stable DNS/resolver in the pod spec (dnsPolicy) if resolution is flaky

Example fix

// before: pod has no egress -> 'Error fetching file ... [Errno -2] Name or service not known'
// after
export HTTPS_PROXY="http://proxy.corp.internal:3128"
export SSL_CERT_FILE="/etc/ssl/certs/corp-ca-bundle.crt"
python -m myapp  # BitBucketClient now reaches api.bitbucket.org
Defensive patterns

Strategy: retry

Validate before calling

import socket, urllib.request

host = "api.bitbucket.org"
try:
    socket.getaddrinfo(host, 443)
except socket.gaierror:
    raise RuntimeError(f"cannot resolve {host}; fix DNS/egress before using BitBucketClient")
# optional reachability probe
try:
    urllib.request.urlopen(f"https://{host}/2.0", timeout=5)
except Exception as e:
    raise RuntimeError(f"no route to {host}: {e}")

Try / catch

import random, time

for attempt in range(3):
    try:
        content = client.get_file_content(path)
        break
    except Exception as e:
        if "Error fetching file" in str(e) and attempt < 2:  # transport-level only
            time.sleep(2 ** attempt + random.random())
            continue
        raise

Prevention

When it happens

Trigger: K8s pod without egress to api.bitbucket.org (network policy/air-gapped cluster); corporate proxy required but HTTP_PROXY/HTTPS_PROXY unset; TLS-intercepting middlebox with an untrusted CA making verification fail; self-hosted base_url unreachable; IPv6/DNS misconfiguration.

Common situations: Services moved into a restricted network segment; certificates rotated on the interception proxy; CI runners behind NAT with flaky DNS; local dev on VPN split-tunnel that drops the API host.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/cc4731c261e79254. Report an issue: GitHub.

Appendix: source

Thrown at litellm/integrations/bitbucket/bitbucket_client.py:118

                    return base64.b64decode(response.content).decode("utf-8")
                except Exception:
                    return response.text

        except Exception as e:
            # Check if it's an HTTP error
            if hasattr(e, "response") and hasattr(e.response, "status_code"):
                if e.response.status_code == 404:
                    return None
                elif e.response.status_code == 403:
                    raise Exception(
                        f"Access denied to file '{file_path}'. Check your BitBucket permissions for workspace '{self.workspace}' and repository '{self.repository}'."
                    )
                elif e.response.status_code == 401:
                    raise Exception("Authentication failed. Check your BitBucket access token and permissions.")
                else:
                    raise Exception(f"Failed to fetch file '{file_path}': {e}")
            else:
                raise Exception(f"Error fetching file '{file_path}': {e}")

    def list_files(self, directory_path: str = "", file_extension: str = ".prompt") -> list[str]:
        """
        List files in a directory with a specific extension.

        Args:
            directory_path: Directory path in the repository (empty for root)
            file_extension: File extension to filter by (default: .prompt)

        Returns:
            List of file paths
        """
        safe_dir: Final = _sanitize_file_path(directory_path) if directory_path else ""
        url: Final = f"{self.base_url}/repositories/{self.workspace}/{self.repository}/src/{self.branch}/{safe_dir}"

        try:
            response: Final = self.http_handler.get(url, headers=self.headers)
            response.raise_for_status()

View on GitHub (pinned to 77b7c6c40c)