{"record":{"id":"68e4ef105e4acf38","repo":"Dokploy/dokploy","slug":"failed-to-fetch-branches-branchesresponse-statu","errorCode":null,"errorMessage":"Failed to fetch branches: ${branchesResponse.statusText}","messagePattern":"Failed to fetch branches: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/utils/providers/gitlab.ts","lineNumber":237,"sourceCode":"\tconst allBranches = [];\n\tlet page = 1;\n\tconst perPage = 100; // GitLab's max per page is 100\n\tconst baseUrl = (\n\t\tgitlabProvider.gitlabInternalUrl || gitlabProvider.gitlabUrl\n\t).replace(/\\/+$/, \"\");\n\n\twhile (true) {\n\t\tconst branchesResponse = await fetch(\n\t\t\t`${baseUrl}/api/v4/projects/${input.id}/repository/branches?page=${page}&per_page=${perPage}`,\n\t\t\t{\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${gitlabProvider.accessToken}`,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\tif (!branchesResponse.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to fetch branches: ${branchesResponse.statusText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst branches = await branchesResponse.json();\n\n\t\tif (branches.length === 0) {\n\t\t\tbreak;\n\t\t}\n\n\t\tallBranches.push(...branches);\n\t\tpage++;\n\n\t\t// Check if we've reached the total using headers (optional optimization)\n\t\tconst total = branchesResponse.headers.get(\"x-total\");\n\t\tif (total && allBranches.length >= Number.parseInt(total)) {\n\t\t\tbreak;\n\t\t}","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/Dokploy/dokploy/blob/546686ea3587f12ec5652217dedd9f7960fb6d15/packages/server/src/utils/providers/gitlab.ts#L219-L255","documentation":"GitLab's GET /projects/:id/repository/branches API returned a non-2xx status while listing branches for a project. The request uses the provider's stored accessToken as a Bearer token, so failures usually mean the token is invalid/expired or the project path is wrong/inaccessible.","triggerScenarios":"Expired or revoked access token (refresh not run before this call), token lacking read_repository scope, project deleted or path changed (404), or insufficient permission (403) on a group project.","commonSituations":"Access token expired between listing repositories and fetching branches; user lost access to the group; project renamed so the stored path 404s.","solutions":["Refresh the access token before fetching branches (call refreshGitlabToken first)","Confirm the project path/ID passed to the branches endpoint is correct and the project exists","Ensure the OAuth app has api/read_repository scope and the user has Developer+ access","Read branchesResponse.status and body to distinguish 401 vs 403 vs 404"],"exampleFix":"// before\nif (!branchesResponse.ok) {\n  throw new Error(`Failed to fetch branches: ${branchesResponse.statusText}`);\n}\n\n// after\nif (!branchesResponse.ok) {\n  const body = await branchesResponse.text();\n  throw new Error(`Failed to fetch branches: ${branchesResponse.status} ${body}`);\n}","handlingStrategy":"try-catch","validationCode":"await refreshGitlabToken(gitlabId); // ensure fresh token before listing branches","typeGuard":null,"tryCatchPattern":"try {\n  return await getGitlabBranches(...);\n} catch (e) {\n  if (e instanceof Error && /fetch branches/.test(e.message)) {\n    // check project existence and scopes before surfacing to user\n  }\n  throw e;\n}","preventionTips":["Refresh tokens before every GitLab API batch","Require read_repository scope on the OAuth app"],"tags":["gitlab","branches","http","api"],"backgroundTag":"api-request-unauthorized","analyzedSha":"546686ea3587f12ec5652217dedd9f7960fb6d15","analyzedAt":"2026-08-27T05:18:58.095Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}