gitroomhq/postiz-app · warning · Error

Account is already activated

Error message

Account is already activated

What it means

Thrown by resendActivationEmail when the target user record already has its 'activated' flag set. The service refuses to generate and send a new activation JWT for an account that no longer needs one. This is a domain-state guard, not a bug indicator.

Source

Thrown at apps/backend/src/services/auth/auth.service.ts:276

      await this._userService.activateUser(user.id);
      user.activated = true;
      this._track('register', user.email, tracking).catch((err) => {});
      await NewsletterService.register(user.email);
      return this.jwt(user as any);
    }

    return false;
  }

  async resendActivationEmail(email: string) {
    const user = await this._userService.getUserByEmail(email);

    if (!user) {
      throw new Error('User not found');
    }

    if (user.activated) {
      throw new Error('Account is already activated');
    }

    const jwt = await this.jwt(user);

    await this._emailService.sendEmail(
      user.email,
      'Activate your account',
      `Click <a href="${process.env.FRONTEND_URL}/auth/activate/${jwt}">here</a> to activate your account`,
      'top'
    );

    return true;
  }

  oauthLink(provider: string, query?: any) {
    const providerInstance = this._providerManager.getProvider(provider);
    return providerInstance.generateLink(query);
  }

View on GitHub (pinned to 0f1647f749)

Solutions

  1. Confirm the user actually needs activation (check the activated column) before calling the endpoint
  2. Have the frontend refresh user state after activation and hide the 'resend email' button
  3. Treat this error as a 200-level 'nothing to do' case in the controller / UI instead of showing a failure
  4. Audit for accidental re-use of the resend flow as a login trigger

Example fix

// before
await authService.resendActivationEmail(user.email);

// after
const user = await userService.getUserByEmail(email);
if (user?.activated) {
  return { alreadyActivated: true };
}
await authService.resendActivationEmail(email);
Defensive patterns

Strategy: validation

Validate before calling

const user = await userService.getUserByEmail(email);
if (!user || user.activated) {
  // nothing to send
  return { ok: true, alreadyActivated: Boolean(user?.activated) };
}
await authService.resendActivationEmail(email);

Type guard

const isUnactivatedUser = (u: User | null): u is User & { activated: false } =>
  !!u && typeof u.activated === 'boolean' && !u.activated;

Try / catch

try {
  await authService.resendActivationEmail(email);
} catch (e) {
  if (e instanceof Error && e.message === 'Account is already activated') return { ok: true };
  throw e;
}

Prevention

When it happens

Trigger: Calling the resend-activation endpoint with the email/identifier of a user whose `user.activated` is true in the database (e.g. POST /auth/resend-activation after the user already clicked the activation link).

Common situations: User double-clicks the resend button after activating in another tab; frontend keeps a stale 'not activated' state; testing with a seed account that is already activated.

Related errors


AI-assisted analysis of gitroomhq/postiz-app@0f1647f749 (2026-08-27). Data as JSON: /api/errors/06952098722d8a67. Report an issue: GitHub.