Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt

Use this file to discover all available pages before exploring further.

Error response format

All API errors use the same envelope:
{
  "success": false,
  "error": {
    "code": "TOKEN_REUSE_DETECTED",
    "message": "This refresh token has already been used. Your session has been revoked for security."
  }
}
For validation errors, an additional details field maps each invalid field to an array of messages:
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": {
      "email": ["'Email' must not be empty.", "'Email' is not a valid email address."],
      "password": ["'Password' must be at least 8 characters."]
    }
  }
}

Error code reference

CodeHTTP statusWhen it occurs
VALIDATION_ERROR400Request body or query parameters failed FluentValidation rules. The details field contains field-level messages.
EMAIL_NOT_VERIFIED400A user attempts to log in before verifying their email address.
INVALID_TOKEN400A token (email verification, password reset, magic link, invitation) is invalid — malformed, already used, or belongs to a different user.
INVITATION_EMAIL_MISMATCH400The logged-in user’s email does not match the email the invitation was sent to.
REGISTRATION_REQUIRED400An invitation acceptance was attempted but no account exists for the invited email. The frontend should redirect to registration.
DUPLICATE_EMAIL409Registration attempted with an email address that is already in use. The error message is generic to avoid confirming whether an account exists.
INVALID_CREDENTIALS401Login failed due to incorrect email or password.
TOKEN_REUSE_DETECTED401A refresh token that has already been used (revoked) was submitted. The entire token family is revoked. The user must log in again.
TOKEN_EXPIRED401A refresh token has passed its expiry date (7 days).
UNAUTHORIZED401No valid JWT was provided, or the JWT is malformed, expired, or has an invalid signature.
FORBIDDEN403The authenticated user does not have the required permission for this action.
NOT_FOUND404The requested resource does not exist, or exists but belongs to a different tenant (intentionally indistinguishable).
CONFLICT409The operation conflicts with the current state. Examples: creating a tenant with a slug already in use, deleting a role that has members assigned, removing the Owner from a tenant.
PAYMENT_REQUIRED402The requested feature requires an active paid subscription.
INTERNAL_ERROR500An unexpected server error occurred. In Production, no details are included. In Development, the exception message and stack trace are included.

Handling errors in the frontend

The Axios instance in AspFox’s frontend has a response interceptor that normalizes error responses. In your feature code, you can check error.response.data.error.code:
import { useMutation } from '@tanstack/react-query';
import { api } from '@/lib/axios';
import { isAxiosError } from 'axios';

const mutation = useMutation({
  mutationFn: async (data: LoginRequest) => {
    const response = await api.post('/api/v1/auth/login', data);
    return response.data.data;
  },
  onError: (error) => {
    if (isAxiosError(error)) {
      const code = error.response?.data?.error?.code;
      if (code === 'EMAIL_NOT_VERIFIED') {
        setShowResendVerification(true);
      } else if (code === 'INVALID_CREDENTIALS') {
        setFieldError('password', 'Incorrect email or password.');
      }
    }
  },
});
TanStack Query surfaces errors in mutation.error and query.error. The Axios interceptor handles 401 UNAUTHORIZED globally — it attempts a token refresh and retries the request before surfacing the error to your component.