BerriAI/litellm · error · Exception
Access denied to file
Error message
Access denied to file '{file_path}'. Check your BitBucket permissions for workspace '{self.workspace}' and repository '{self.repository}'. What it means
get_file_content received HTTP 403 from GET /repositories/{workspace}/{repository}/src/{branch}/{path}: authentication succeeded (otherwise 401) but the credential is not permitted to read this resource — the token/app password lacks repository read scope, the account is not a member of the workspace, or workspace SSO/IP restrictions block it. The original HTTP details are discarded and only this generic message is raised.
Solutions
- Recreate the token/app password granting repository read scope (app passwords: tick Repositories -> Read)
- Verify the authenticating account has at least read access to that workspace/repo (workspace -> Members / repo -> Permissions)
- If the workspace requires SSO, approve/authorize the token for that workspace in Atlassian account settings
- Double-check workspace and repository spelling — BitBucket can return 403 rather than 404 for repos hidden from your identity
Example fix
// before: token without repo read scope
BitBucketClient({"workspace": "acme", "repository": "prompt-library", "access_token": narrow_token})
// after: app password with Repositories:Read, basic auth
BitBucketClient({"workspace": "acme", "repository": "prompt-library",
"access_token": os.environ["BITBUCKET_APP_PASSWORD"],
"auth_method": "basic", "username": "svc-prompts"}) Defensive patterns
Strategy: try-catch
Validate before calling
# No API to pre-check scopes without a request; verify access cheaply:
probe = client.list_files("") # or get_file_content("README.md")
# 403 on the probe means the token cannot read this repo at all Try / catch
try:
content = client.get_file_content("prompts/triage.prompt")
except Exception as e:
if "Access denied" in str(e):
logger.error("bitbucket 403: token lacks repository read scope for %s/%s",
client.workspace, client.repository)
raise
raise Prevention
- Create tokens/app passwords with exactly Repositories:Read for prompt fetching
- Verify the service account's workspace membership when onboarding a new repo
- Authorize tokens under workspace SSO before deploying
- Run a read probe at startup to fail fast with a clear message instead of mid-request
When it happens
Trigger: API token with only account/snippet scopes but not repository:read; app password created without the 'Repositories: Read' permission; repository private to another team in the same workspace; SSO-protected workspace where the token was never authorized; branch-level restrictions on the requested branch.
Common situations: Rotating to a least-privilege token that turned out too narrow; org tokens vs personal tokens confusion; on-prem-style SSO enforcement enabled after the token was created; new repos defaulting to private.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Access denied to directory
- access_denied
- Access denied to prompt version
- forbidden
- User not allowed to call this tool.
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/b1de80c3c88a7cd3.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/integrations/bitbucket/bitbucket_client.py:110
response.raise_for_status()
# BitBucket returns file content as base64 encoded
if response.headers.get("content-type", "").startswith("text/"):
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:View on GitHub (pinned to 77b7c6c40c)