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

  1. Treat the error as idempotent: fetch the request and check its current status before surfacing a failure.
  2. Disable review actions in the UI once a request is no longer pending.
  3. 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

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


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/fef8e9caa7cfb4af. Report an issue: GitHub.