BerriAI/litellm · error · Exception

Access denied to directory '{directory_path}'. Check your Gi

Error message

Access denied to directory '{directory_path}'. Check your GitLab permissions for project '{self.project}'.

What it means

GitLab answered 403 Forbidden for the repository tree API used by list_files (GET /projects/<id>/repository/tree?ref=...). The token authenticated but cannot read this project/directory: role below Reporter on a private project, missing read_repository scope, or a path under a repo the identity cannot see. Note that a 404 returns an empty list instead of raising, so this error specifically means the identity is being denied, not that the path is missing.

Source

Thrown at litellm/integrations/gitlab/gitlab_client.py:225

            if resp.status_code == 404:
                return []
            resp.raise_for_status()

            data: Final = resp.json() or []
            files: Final[list[str]] = []
            for item in data:
                if item.get("type") == "blob":
                    file_path = item.get("path", "")
                    if not file_extension or file_path.endswith(file_extension):
                        files.append(file_path)
            return files

        except Exception as e:
            status: Final = getattr(getattr(e, "response", None), "status_code", None)
            if status == 404:
                return []
            if status == 403:
                raise Exception(
                    f"Access denied to directory '{directory_path}'. Check your GitLab permissions for project '{self.project}'."
                )
            if status == 401:
                raise Exception("Authentication failed. Check your GitLab token and auth_method.")
            raise Exception(f"Failed to list files in '{directory_path}': {e}")

    def get_repository_info(self) -> dict[str, Any]:
        """Get information about the project/repository."""
        url: Final = f"{self.base_url}/projects/{self._project_enc}"
        try:
            resp: Final = self.http_handler.get(url, headers=self.headers)
            resp.raise_for_status()
            return resp.json()
        except Exception as e:
            raise Exception(f"Failed to get repository info: {e}")

    def test_connection(self) -> bool:
        """Test the connection to the GitLab project."""

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. Confirm the token's user can browse that directory in the GitLab UI
  2. Use read_repository scope and Reporter+ role on the project
  3. Check the directory path spelling/case and that it lives in the configured project
  4. Verify you pointed at the right project (a wrong project that exists and is private yields 403)

Example fix

# before: token without repository read on a private project
files = client.list_files("prompts/internal")

# after: token with read_repository scope and a path the identity can see
files = client.list_files("prompts")
Defensive patterns

Strategy: try-catch

Validate before calling

# Fail fast at startup instead of discovering 403s during prompt listing
if not client.test_connection():
    raise RuntimeError("GitLab credentials/project invalid")
client.list_files("prompts")  # exercises the tree API at boot

Try / catch

try:
    files = client.list_files("prompts")
except Exception as e:
    if "Access denied to directory" in str(e):
        raise RuntimeError(
            "Token cannot list the prompts directory - "
            "grant read_repository / Reporter+ or fix the path"
        ) from e
    raise

Prevention

When it happens

Trigger: list_files('prompts') with a Guest-role token; PAT without read_repository scope; directory path belonging to a different (private) subgroup repo; protected ref with an unprivileged token.

Common situations: Startup prompt discovery running with a least-privilege CI token; org restructures moving repositories between groups; scope changes after token rotation.

Understand the failure class

Related errors


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