{"record":{"id":"b1de80c3c88a7cd3","repo":"BerriAI/litellm","slug":"access-denied-to-file-file-path-check-your-bi","errorCode":null,"errorMessage":"Access denied to file '{file_path}'. Check your BitBucket permissions for workspace '{self.workspace}' and repository '{self.repository}'.","messagePattern":"Access denied to file '(.+?)'\\. Check your BitBucket permissions for workspace '(.+?)' and repository '(.+?)'\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/bitbucket/bitbucket_client.py","lineNumber":110,"sourceCode":"            response.raise_for_status()\n\n            # BitBucket returns file content as base64 encoded\n            if response.headers.get(\"content-type\", \"\").startswith(\"text/\"):\n                return response.text\n            else:\n                # For binary files or when content-type is not text, try to decode as base64\n                try:\n                    return base64.b64decode(response.content).decode(\"utf-8\")\n                except Exception:\n                    return response.text\n\n        except Exception as e:\n            # Check if it's an HTTP error\n            if hasattr(e, \"response\") and hasattr(e.response, \"status_code\"):\n                if e.response.status_code == 404:\n                    return None\n                elif e.response.status_code == 403:\n                    raise Exception(\n                        f\"Access denied to file '{file_path}'. Check your BitBucket permissions for workspace '{self.workspace}' and repository '{self.repository}'.\"\n                    )\n                elif e.response.status_code == 401:\n                    raise Exception(\"Authentication failed. Check your BitBucket access token and permissions.\")\n                else:\n                    raise Exception(f\"Failed to fetch file '{file_path}': {e}\")\n            else:\n                raise Exception(f\"Error fetching file '{file_path}': {e}\")\n\n    def list_files(self, directory_path: str = \"\", file_extension: str = \".prompt\") -> list[str]:\n        \"\"\"\n        List files in a directory with a specific extension.\n\n        Args:\n            directory_path: Directory path in the repository (empty for root)\n            file_extension: File extension to filter by (default: .prompt)\n\n        Returns:","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/bitbucket/bitbucket_client.py#L92-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: token without repo read scope\nBitBucketClient({\"workspace\": \"acme\", \"repository\": \"prompt-library\", \"access_token\": narrow_token})\n// after: app password with Repositories:Read, basic auth\nBitBucketClient({\"workspace\": \"acme\", \"repository\": \"prompt-library\",\n                 \"access_token\": os.environ[\"BITBUCKET_APP_PASSWORD\"],\n                 \"auth_method\": \"basic\", \"username\": \"svc-prompts\"})","handlingStrategy":"try-catch","validationCode":"# No API to pre-check scopes without a request; verify access cheaply:\nprobe = client.list_files(\"\")  # or get_file_content(\"README.md\")\n# 403 on the probe means the token cannot read this repo at all","typeGuard":null,"tryCatchPattern":"try:\n    content = client.get_file_content(\"prompts/triage.prompt\")\nexcept Exception as e:\n    if \"Access denied\" in str(e):\n        logger.error(\"bitbucket 403: token lacks repository read scope for %s/%s\",\n                     client.workspace, client.repository)\n        raise\n    raise","preventionTips":["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"],"tags":["bitbucket","http-403","permissions","authorization","api"],"backgroundTag":"http-403-forbidden","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}