{"record":{"id":"8fbfe63249f393f3","repo":"BloopAI/vibe-kanban","slug":"result-message-force-push-failed","errorCode":null,"errorMessage":"result.message || 'Force push failed'","messagePattern":"result\\.message \\|\\| 'Force push failed'","errorType":"exception","errorClass":"ForcePushErrorWithData","httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/hooks/useForcePush.ts","lineNumber":27,"sourceCode":"  ) {\n    super(message);\n    this.name = 'ForcePushErrorWithData';\n  }\n}\n\nexport function useForcePush(\n  workspaceId?: string,\n  onSuccess?: () => void,\n  onError?: (err: unknown, errorData?: PushError) => void\n) {\n  const queryClient = useQueryClient();\n\n  return useMutation<void, unknown, PushWorkspaceRequest>({\n    mutationFn: async (params: PushWorkspaceRequest) => {\n      if (!workspaceId) return;\n      const result = await workspacesApi.forcePush(workspaceId, params);\n      if (!result.success) {\n        throw new ForcePushErrorWithData(\n          result.message || 'Force push failed',\n          result.error\n        );\n      }\n    },\n    onSuccess: () => {\n      // A force push affects remote status; invalidate the same branchStatus\n      queryClient.invalidateQueries({\n        queryKey: ['branchStatus', workspaceId],\n      });\n      onSuccess?.();\n    },\n    onError: (err) => {\n      console.error('Failed to force push:', err);\n      const errorData =\n        err instanceof ForcePushErrorWithData ? err.errorData : undefined;\n      onError?.(err, errorData);\n    },","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/hooks/useForcePush.ts#L9-L45","documentation":"The forcePush mutation calls workspacesApi.forcePush; if the response reports success=false it throws ForcePushErrorWithData carrying the server-provided message (result.message) or the fallback string 'Force push failed'. It is a generic wrapper around any server-side rejection of a force push, and the response's error field is attached for downstream handling.","triggerScenarios":"Invoking force push on a workspace when the backend rejects it: remote Git authentication failure (bad/expired credentials or token), the underlying git push --force process fails, the workspace/attempt is currently running and locked, or the remote repository refuses the force push (e.g. protected branch).","commonSituations":"Expired GitHub/GitLab PAT after rotation or SSO deauthorization; pushing to a branch protected by branch-protection rules; concurrent execution holding the workspace lock; wrong remote URL or network outage during the push.","solutions":["Read result.error/result.message in the ForcePushErrorWithData for the server's specific cause and fix that underlying issue","Re-authenticate the Git provider (refresh or regenerate the OAuth token/PAT) in settings and retry","Stop any running attempt/process on the workspace so it is not locked, then force push again","Check branch-protection rules on the remote if pushing to a protected branch, or push to a different branch","Verify network connectivity and the remote URL in the workspace's Git settings"],"exampleFix":"// before\nthrow new ForcePushErrorWithData(\n  result.message || 'Force push failed',\n  result.error\n);\n// after\nthrow new ForcePushErrorWithData(\n  result.message || `Force push failed (workspace ${workspaceId})`,\n  result.error\n);\n// caller:\ntry {\n  forcePush({ ... });\n} catch (e) {\n  if (e instanceof ForcePushErrorWithData) showToast(e.message, e.error);\n}","handlingStrategy":"try-catch","validationCode":"// Before force pushing: ensure workspace is idle and remote creds are valid\nif (workspace.isAttemptRunning) return showToast('Stop the running attempt first');\nconst status = await gitApi.getAuthStatus?.();\nif (status && !status.authenticated) return promptReauth();","typeGuard":"function isForcePushError(e: unknown): e is ForcePushErrorWithData {\n  return e instanceof ForcePushErrorWithData;\n}","tryCatchPattern":"useMutation({...}).mutateAsync(params).catch((e) => {\n  if (isForcePushError(e)) {\n    showToast(e.message); // e.error holds the structured server reason\n  } else {\n    showToast('Unexpected force push error');\n  }\n});","preventionTips":["Re-authenticate the Git provider when tokens are rotated or expire","Avoid force pushing to protected branches","Stop running attempts before pushing to avoid workspace locks","Surface result.error details in UI instead of only the fallback message"],"tags":["git","force-push","api-error","react-query"],"backgroundTag":"git-push-failed","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}