BerriAI/litellm · error · Exception
Authentication failed. Check your BitBucket access token…
Error message
Authentication failed. Check your BitBucket access token and permissions.
What it means
get_file_content received HTTP 401 from the BitBucket src endpoint: the credential itself was rejected — expired or revoked app password/access token, a malformed Bearer header, or an auth-mode mismatch where app-password credentials are sent as a Bearer token (the client defaults to auth_method="token"; basic auth with username is only used when configured).
Solutions
- Regenerate the app password / access token and update the config or vault it came from
- For app passwords set auth_method="basic" and username so the client sends Basic auth instead of Bearer
- Trim whitespace/newlines when loading the secret (e.g., .strip() on env reads)
- Restart the process after credential rotation so the cached client headers are rebuilt
Example fix
// before
BitBucketClient({"workspace": "acme", "repository": "r",
"access_token": app_password}) # default Bearer -> 401
// after
BitBucketClient({"workspace": "acme", "repository": "r",
"access_token": app_password,
"auth_method": "basic", "username": "svc-prompts"}) Defensive patterns
Strategy: try-catch
Validate before calling
import base64, os
token = os.environ.get("BITBUCKET_APP_PASSWORD", "").strip()
if not token:
raise RuntimeError("BITBUCKET_APP_PASSWORD is empty or unset") Type guard
def looks_like_credential(secret: str) -> bool:
s = (secret or "").strip()
return len(s) >= 20 and not any(c.isspace() for c in s) Try / catch
try:
content = client.get_file_content(path)
except Exception as e:
if "Authentication failed" in str(e):
logger.error("bitbucket 401: credential expired/revoked or wrong auth_method")
raise
raise Prevention
- Set auth_method="basic" + username when using app passwords (default Bearer will 401)
- .strip() secrets read from env/files — trailing newlines break auth
- Rotate credentials in the vault and restart so headers rebuild
- Distinguish 401 (credential bad) from 403 (credential fine, no permission) before debugging scopes
When it happens
Trigger: App password revoked when the owning account changed/rotated it; sending an app password with the default Bearer scheme; token pasted with whitespace/newlines from a secret file; workspace migrated to API tokens while the old credential type was deprecated.
Common situations: Silent expiry of bitbucket-tokens during long-running services; secrets rotated in vault but not reloaded by the process; copying a token for a different Atlassian product (e.g., a Jira API token).
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- {e}
- Access denied to directory
- Access denied to file
- Authentication failed. Check your Arize Phoenix API key and…
- byok_auth_required
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/0adbe8c16c0d3ad0.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/integrations/bitbucket/bitbucket_client.py:114
return response.text
else:
# For binary files or when content-type is not text, try to decode as base64
try:
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}"View on GitHub (pinned to 77b7c6c40c)