vxcontrol/pentagi · error

token not found in database

Error message

token not found in database

What it means

The bearer token's JWT is valid, but its TokenID has no matching row in the API tokens table (gorm.ErrRecordNotFound from tokenCache.GetStatus), so the middleware fails authentication. This means the token was deleted after issuance, belongs to a wiped/recreated database, or never existed in this installation.

Source

Thrown at backend/pkg/server/auth/auth_middleware.go:225

		return authResultSkip, errors.New("token can't be empty")
	}

	// skip validation if using default salt (for backward compatibility)
	if p.globalSalt == "" || p.globalSalt == "salt" {
		return authResultSkip, errors.New("token validation disabled with default salt")
	}

	// try to validate as API token first (new format with JWT signing key)
	apiClaims, apiErr := ValidateAPIToken(token, p.globalSalt)
	if apiErr != nil {
		return authResultFail, errors.New("token is invalid")
	}

	// check token status and get privileges through cache
	status, privileges, err := p.tokenCache.GetStatus(apiClaims.TokenID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return authResultFail, errors.New("token not found in database")
		}
		return authResultFail, fmt.Errorf("error checking token status: %w", err)
	}
	if status != models.TokenStatusActive {
		return authResultFail, errors.New("token has been revoked")
	}

	// Verify user hash matches database
	dbHash, userStatus, err := p.userCache.GetUserHash(apiClaims.UID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return authResultFail, errors.New("user has been deleted")
		}
		return authResultFail, fmt.Errorf("error checking user status: %w", err)
	}

	if userStatus == models.UserStatusBlocked {
		return authResultFail, errors.New("user has been blocked")

View on GitHub (pinned to ea665308ba)

Solutions

  1. Create a new API token in the current environment's settings UI and replace the client's credential.
  2. Verify the client is pointed at the intended environment (check the API base URL).
  3. If a backup restore removed tokens, reissue them for all automation users.
  4. Audit for scripts still holding old tokens after cleanup and rotate them.

Example fix

// before
const API = "https://prod.example.com";
const token = stagingToken;

// after
const API = "https://prod.example.com";
const token = prodToken; // minted in the same environment as API
Defensive patterns

Strategy: fallback

Validate before calling

# verify the token exists before shipping it to a client:
# SELECT 1 FROM api_tokens WHERE token_id = '<id>' AND status = 'active';

Try / catch

try {
  return await call(token);
} catch (e) {
  if (is401(e) && /not found in database/i.test(e.message)) {
    logger.error("Token unknown to this environment — mint a new one here");
    return await call(await mintNewToken());
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling with an API token whose record was deleted from the tokens table; pointing a client at a different environment (staging token against production DB); restoring the database from a backup that predates the token.

Common situations: Token revoked by deletion rather than status change; environment misconfiguration (wrong DATABASE_URL); CI using a token from a teammate's local instance; DB migration dropping the tokens table data.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/7e5046a0086b6f39. Report an issue: GitHub.