{"record":{"id":"cfaebbc4d6dc32d9","repo":"BerriAI/litellm","slug":"failed-to-list-files-in-directory-path-e-cfaebb","errorCode":null,"errorMessage":"Failed to list files in '{directory_path}': {e}","messagePattern":"Failed to list files in '(.+?)': (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/gitlab/gitlab_client.py","lineNumber":230,"sourceCode":"            files: Final[list[str]] = []\n            for item in data:\n                if item.get(\"type\") == \"blob\":\n                    file_path = item.get(\"path\", \"\")\n                    if not file_extension or file_path.endswith(file_extension):\n                        files.append(file_path)\n            return files\n\n        except Exception as e:\n            status: Final = getattr(getattr(e, \"response\", None), \"status_code\", None)\n            if status == 404:\n                return []\n            if status == 403:\n                raise Exception(\n                    f\"Access denied to directory '{directory_path}'. Check your GitLab permissions for project '{self.project}'.\"\n                )\n            if status == 401:\n                raise Exception(\"Authentication failed. Check your GitLab token and auth_method.\")\n            raise Exception(f\"Failed to list files in '{directory_path}': {e}\")\n\n    def get_repository_info(self) -> dict[str, Any]:\n        \"\"\"Get information about the project/repository.\"\"\"\n        url: Final = f\"{self.base_url}/projects/{self._project_enc}\"\n        try:\n            resp: Final = self.http_handler.get(url, headers=self.headers)\n            resp.raise_for_status()\n            return resp.json()\n        except Exception as e:\n            raise Exception(f\"Failed to get repository info: {e}\")\n\n    def test_connection(self) -> bool:\n        \"\"\"Test the connection to the GitLab project.\"\"\"\n        try:\n            self.get_repository_info()\n            return True\n        except Exception:\n            return False","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/gitlab/gitlab_client.py#L212-L248","documentation":"Catch-all wrapping any non-401/403/404 failure of the tree request in list_files, with the original exception included. Covers transport errors (DNS, refused connections, TLS), GitLab 5xx, rate limiting (429), and timeouts. A 404 would silently return [], so reaching this message means a genuine infrastructure or configuration problem, not a missing directory.","triggerScenarios":"Self-hosted GitLab unreachable or restarting; 429 rate limiting from aggressive polling; 5xx during GitLab incidents; TLS/proxy failures; timeouts enumerating very large trees (no pagination parameters are sent).","commonSituations":"Startup prompt discovery hitting a sleeping on-prem instance; CI jobs hammering the tree API; GitLab.com degradation; huge repositories with thousands of entries.","solutions":["Confirm the GitLab host is up and base_url includes /api/v4","Add backoff/jitter and cache directory listings between runs","Retry transient 5xx/429 responses","Reduce scope: pass a narrower directory_path instead of listing recursively from the root"],"exampleFix":"# before: recursive listing of the whole repo on every boot\nfiles = client.list_files(recursive=True)\n\n# after: scope the listing to the prompts directory\nfiles = client.list_files(\"prompts\", recursive=True)","handlingStrategy":"retry","validationCode":"import httpx\n\n\ndef can_list_now(client) -> bool:\n    \"\"\"Cheap readiness check for the tree API before a big listing.\"\"\"\n    try:\n        client.list_files(\"\")  # single page, root only\n        return True\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"import time\n\n\ndef list_with_retry(client, path, attempts=3):\n    for i in range(attempts):\n        try:\n            return client.list_files(path)\n        except Exception as e:\n            msg = str(e)\n            retryable = \"Failed to list files\" in msg and any(\n                t in msg for t in (\"timed out\", \"ConnectError\", \"500\", \"502\", \"503\", \"429\")\n            )\n            if i == attempts - 1 or not retryable:\n                raise\n            time.sleep(2 ** i)","preventionTips":["Cache the prompt file listing; refresh on a schedule, not per request","Rate-limit discovery loops to stay under GitLab's limits","Scope listings to the prompts directory to keep responses small"],"tags":["gitlab","network","http","tree-api"],"backgroundTag":"http-request-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}