# Errors
`nythos-core` uses a single error enum: `AuthError`.
## Purpose
`AuthError` is the common failure type for domain and application-level auth
logic inside the core.
It exists to:
- keep error handling consistent across modules
- express expected auth and authorization failures in domain terms
- avoid leaking transport or infrastructure concerns into the core API
The standard result alias is:
```rust
pub type NythosResult<T> = Result<T, AuthError>;
```
## Variants
## `UserNotFound`
Return when the requested user does not exist in the relevant tenant scope.
Typical cases:
- lookup by ID fails
Current flow note:
- login does not currently return `UserNotFound`; it collapses missing-user login into `InvalidCredentials`
## `InvalidCredentials`
Return when credentials do not authenticate successfully.
Typical cases:
- login flow cannot find the user
- wrong password
- unknown refresh token presented to refresh
- reuse of a rotated refresh token during refresh
## `AccountLocked`
Return when the user exists but authentication is blocked because the account is locked.
Typical cases:
- lockout policy triggered after repeated failures
- account was locked by an admin or domain rule
- disabled account currently maps here in the login flow as well
## `SessionRevoked`
Return when a session or refresh credential is no longer valid because it was revoked.
Typical cases:
- refresh sees a returned session marked revoked
- refresh sees external revocation through `RevocationChecker`
- revoke-one currently surfaces this error when the target session does not exist in the store contract
## `SessionExpired`
Return when session lifetime is over and refresh or session-based continuation is no longer allowed.
Typical cases:
- refresh attempted after session expiry
- outer layer checks session state and sees it is expired
## `TenantNotFound`
Return when a required tenant context does not exist.
Typical cases:
- tenant-scoped operation references an unknown tenant
- a repository or service maps missing tenant state into a core error
## `PermissionDenied`
Return when an authenticated actor lacks the required permission in the current tenant scope.
Typical cases:
- role and permission evaluation fails authorization
- user attempts tenant action without the required assignment
## `ValidationError(String)`
Return when input fails domain validation.
Typical cases:
- malformed email
- invalid password input shape
- invalid slug or role name format
The message should be practical and implementation-useful, not transport-formatted.
## `Internal(String)`
Return when a failure occurs that the core cannot classify as an expected domain error.
Typical cases:
- hasher implementation failure
- signer failure
- repository or store failure that does not map to a known domain condition
Use this sparingly. Prefer a specific domain variant when the failure is expected
and meaningful to callers.
## Expected Failures vs Internal Failures
Expected domain failures are part of normal auth behavior.
Examples:
- wrong password
- revoked session
- missing tenant
- permission denied
Internal failures indicate that a required dependency or operation failed in a
way the core does not model directly.
Examples:
- token-signing backend failed
- password hasher returned an unexpected error
- persistence layer failed unexpectedly
This distinction matters because outer layers may log, retry, alert, or map
these cases differently.
## Current Flow Semantics
The current implementation uses the variants above with the following concrete
auth-flow semantics.
These notes document the current implementation, not a permanent product-policy
commitment.
## Login
- missing-user login returns `AuthError::InvalidCredentials`
- wrong-password login returns `AuthError::InvalidCredentials`
- locked user login returns `AuthError::AccountLocked`
- disabled user login currently returns `AuthError::AccountLocked`
## Refresh
- unknown refresh token returns `AuthError::InvalidCredentials`
- reuse of a rotated refresh token returns `AuthError::InvalidCredentials`
- a returned session record already marked revoked returns `AuthError::SessionRevoked`
- external revocation through `RevocationChecker` returns `AuthError::SessionRevoked`
- expired session refresh returns `AuthError::SessionExpired`
- refresh at exactly the expiry boundary returns `AuthError::SessionExpired` because expiry checks use `expires_at <= now`
## Revocation
- revoke-one checks `RevocationChecker` before calling `SessionStore::revoke_session`
- if `RevocationChecker` already reports the session as revoked, revoke-one returns success with `RevokeResult::revoked() == false`
- revoke-one for a missing session currently surfaces `AuthError::SessionRevoked`
- revoke-all returns success with `RevokeResult::revoked() == true` when the store call succeeds
- revoke-all currently returns success from the service even when no sessions match, as long as the store call itself succeeds
## HTTP Mapping Stays Outside The Core
`nythos-core` never maps `AuthError` to:
- HTTP status codes
- gRPC status codes
- REST error envelopes
- framework exceptions
That mapping belongs in outer layers.