{"record":{"id":"f47200b532b56190","repo":"BerriAI/litellm","slug":"access-denied-to-directory-directory-path-che","errorCode":null,"errorMessage":"Access denied to directory '{directory_path}'. Check your BitBucket permissions for workspace '{self.workspace}' and repository '{self.repository}'.","messagePattern":"Access denied to directory '(.+?)'\\. Check your BitBucket permissions for workspace '(.+?)' and repository '(.+?)'\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/bitbucket/bitbucket_client.py","lineNumber":155,"sourceCode":"\n            data: Final = response.json()\n            files: Final = []\n\n            for item in data.get(\"values\", []):\n                if item.get(\"type\") == \"commit_file\":\n                    file_path = item.get(\"path\", \"\")\n                    if file_path.endswith(file_extension):\n                        files.append(file_path)\n\n            return files\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 []\n                elif e.response.status_code == 403:\n                    raise Exception(\n                        f\"Access denied to directory '{directory_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 list files in '{directory_path}': {e}\")\n            else:\n                raise Exception(f\"Error listing files in '{directory_path}': {e}\")\n\n    def get_repository_info(self) -> dict[str, Any]:\n        \"\"\"\n        Get information about the repository.\n\n        Returns:\n            Dictionary containing repository information\n        \"\"\"\n        url: Final = f\"{self.base_url}/repositories/{self.workspace}/{self.repository}\"\n","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/bitbucket/bitbucket_client.py#L137-L173","documentation":"Raised by BitBucketClient.list_files when the BitBucket API responds 403 while enumerating a directory. Mirrors get_file's 403 handling but for the directory listing endpoint: credentials authenticated, yet the token/account cannot read that directory in the workspace/repository. 404 maps to [] (empty list), so only permission problems raise here.","triggerScenarios":"Calling list_files(directory_path=...) on a directory the token cannot read; app password without repository read scope; workspace/repo values pointing at a private repo the credential owner is not a member of; branch inaccessible.","commonSituations":"Token scoped to a different repository than the one configured; directory inside a submodule or restricted folder; team permission changes after the integration was set up; scanning the repo root when the token only covers specific paths.","solutions":["Grant the credential's account read access to the repository (or recreate the app password with repository:read scope)","Confirm workspace/repository spellings and that the directory exists in that repo","Test access in the UI as the token owner, or curl https://api.bitbucket.org/2.0/repositories/<ws>/<repo>/src/<branch>/<dir> with the token","Narrow directory_path to a directory you know is readable"],"exampleFix":"# before\ntoken = account_scoped_app_password  # no repo scope\nclient.list_files(\"prompts\")  # 403 -> Exception\n\n# after\n# app password with Repository access: Read\ntoken = repo_read_app_password\nclient.list_files(\"prompts\")","handlingStrategy":"try-catch","validationCode":"import httpx\n\ndef can_list_directory(workspace: str, repo: str, directory: str, token: str, branch: str = \"main\") -> bool:\n    url = f\"https://api.bitbucket.org/2.0/repositories/{workspace}/{repo}/src/{branch}/{directory}\"\n    r = httpx.get(url, auth=(\"x-token-auth\", token), timeout=10)\n    return r.status_code == 200","typeGuard":null,"tryCatchPattern":"try:\n    files = client.list_files(directory_path)\nexcept Exception as e:\n    if \"Access denied to directory\" in str(e):\n        raise PermissionError(f\"token cannot list {directory_path}; grant repository read scope\") from e\n    raise","preventionTips":["Grant the credential owner explicit read on the repository, not just the workspace","Pre-flight the list_files call during deployment smoke tests","Remember 404 returns [] silently — a missing directory will not raise, so permission errors are the loud case","Scope tokens per repository and validate them with a direct API smoke test"],"tags":["bitbucket","http-403","permissions","authentication"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}