Tencent/WeKnora · warning
request has already been reviewed
Error message
request has already been reviewed
What it means
ReviewJoinRequest returns this inline error when the target join request exists and belongs to the organization but its Status is not JoinRequestStatusPending — i.e. it was already approved or rejected. This prevents double-processing of a review decision.
Source
Thrown at internal/application/service/organization.go:704
// CountPendingJoinRequests returns the number of pending join requests for an organization
func (s *organizationService) CountPendingJoinRequests(ctx context.Context, orgID string) (int64, error) {
return s.orgRepo.CountJoinRequests(ctx, orgID, types.JoinRequestStatusPending)
}
// ReviewJoinRequest reviews a join request or upgrade request (approve or reject).
// On approve the targeted tenant gets the assigned role; reviewerTenantID is
// only used for audit (the gate is the route-level Admin guard).
func (s *organizationService) ReviewJoinRequest(ctx context.Context, orgID string, requestID string, approved bool, reviewerID string, reviewerTenantID uint64, message string, assignRole *types.OrgMemberRole) error {
request, err := s.orgRepo.GetJoinRequestByID(ctx, requestID)
if err != nil {
return ErrJoinRequestNotFound
}
if request.OrganizationID != orgID {
return ErrJoinRequestNotFound
}
if request.Status != types.JoinRequestStatusPending {
return errors.New("request has already been reviewed")
}
var status types.JoinRequestStatus
if approved {
status = types.JoinRequestStatusApproved
role := types.OrgRoleViewer
if assignRole != nil && assignRole.IsValid() {
role = *assignRole
} else if request.RequestedRole != "" && request.RequestedRole.IsValid() {
role = request.RequestedRole
}
if request.RequestType == types.JoinRequestTypeUpgrade {
if err := s.orgRepo.UpdateTenantMemberRole(ctx, request.OrganizationID, request.TenantID, role); err != nil {
return err
}
logger.Infof(ctx, "Upgrade request %s approved, tenant %d role updated to %s in organization %s", requestID, request.TenantID, role, request.OrganizationID)View on GitHub (pinned to 988cbb0330)
Solutions
- Treat the error as idempotent: fetch the request and check its current status before surfacing a failure.
- Disable review actions in the UI once a request is no longer pending.
- Handle the message match (or add a sentinel) so retries don't report false failures.
Example fix
// before
err := svc.ReviewJoinRequest(ctx, orgID, requestID, true)
if err != nil { return err }
// after
err := svc.ReviewJoinRequest(ctx, orgID, requestID, true)
if err != nil && strings.Contains(err.Error(), "already been reviewed") {
return nil // decision already recorded
} else if err != nil { return err } Defensive patterns
Strategy: try-catch
Validate before calling
req, err := svc.GetJoinRequestByID(ctx, orgID, requestID)
if err == nil && req.Status != types.JoinRequestStatusPending {
return fmt.Errorf("request already %s", req.Status)
} Try / catch
if err != nil && strings.Contains(err.Error(), "already been reviewed") {
return nil // another admin already decided; treat as success
} Prevention
- Disable review buttons for non-pending requests.
- Fetch current status before submitting a review.
- Design review calls as idempotent operations.
When it happens
Trigger: Two admins clicking approve/reject concurrently, or a reviewer retrying after the first click succeeded but the UI did not update; also stale review pages listing already-decided requests.
Common situations: Double-click submissions, review queues cached beyond the decision moment, or API retries (at-least-once delivery) replaying an approval.
Related errors
- pending request already exists
- tenant is already an admin
- member_limit must be >= 0
- join request not found
- cannot request upgrade to same or lower role
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/fef8e9caa7cfb4af.
Report an issue: GitHub.