{"record":{"id":"a04abc3092bd1390","repo":"vxcontrol/pentagi","slug":"error-checking-token-status-w","errorCode":null,"errorMessage":"error checking token status: %w","messagePattern":"error checking token status: %w","errorType":"exception","errorClass":null,"httpStatus":500,"severity":"error","filePath":"backend/pkg/server/auth/auth_middleware.go","lineNumber":227,"sourceCode":"\n\t// skip validation if using default salt (for backward compatibility)\n\tif p.globalSalt == \"\" || p.globalSalt == \"salt\" {\n\t\treturn authResultSkip, errors.New(\"token validation disabled with default salt\")\n\t}\n\n\t// try to validate as API token first (new format with JWT signing key)\n\tapiClaims, apiErr := ValidateAPIToken(token, p.globalSalt)\n\tif apiErr != nil {\n\t\treturn authResultFail, errors.New(\"token is invalid\")\n\t}\n\n\t// check token status and get privileges through cache\n\tstatus, privileges, err := p.tokenCache.GetStatus(apiClaims.TokenID)\n\tif err != nil {\n\t\tif errors.Is(err, gorm.ErrRecordNotFound) {\n\t\t\treturn authResultFail, errors.New(\"token not found in database\")\n\t\t}\n\t\treturn authResultFail, fmt.Errorf(\"error checking token status: %w\", err)\n\t}\n\tif status != models.TokenStatusActive {\n\t\treturn authResultFail, errors.New(\"token has been revoked\")\n\t}\n\n\t// Verify user hash matches database\n\tdbHash, userStatus, err := p.userCache.GetUserHash(apiClaims.UID)\n\tif err != nil {\n\t\tif errors.Is(err, gorm.ErrRecordNotFound) {\n\t\t\treturn authResultFail, errors.New(\"user has been deleted\")\n\t\t}\n\t\treturn authResultFail, fmt.Errorf(\"error checking user status: %w\", err)\n\t}\n\n\tif userStatus == models.UserStatusBlocked {\n\t\treturn authResultFail, errors.New(\"user has been blocked\")\n\t}\n","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/server/auth/auth_middleware.go#L209-L245","documentation":"In tryProtoTokenAuthentication, after ValidateAPIToken succeeds, p.tokenCache.GetStatus(apiClaims.TokenID) fetches the token's DB status and privileges. Any error other than gorm.ErrRecordNotFound is wrapped as \"error checking token status: %w\" — the token's database state could not be read, so the request cannot be authorized.","triggerScenarios":"Postgres unavailable or timing out while resolving apiClaims.TokenID; connection-pool exhaustion; missing schema/migrations causing the query to fail; cache layer returning a non-NotFound error.","commonSituations":"DB outage or failover during API traffic; pool exhausted under heavy concurrent API-token usage; incomplete migrations on a fresh deployment.","solutions":["Check the wrapped %w cause in logs and verify PostgreSQL health/connectivity","Retry the API call if the failure was transient (restart/timeout)","Apply pending migrations and confirm the api_tokens table exists with expected columns","Review tokenCache/db connection-pool settings for the request volume"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-flight: confirm the token exists/active before hammering the API\n// (e.g., via the settings endpoint or a DB check)\n// if tokenStatus(tokenID) != TokenStatusActive { reissueToken() }","typeGuard":"func isTokenStatusError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"error checking token status:\") &&\n        !errors.Is(err, gorm.ErrRecordNotFound)\n}","tryCatchPattern":"resp, err := callAPI()\nif err != nil && strings.Contains(err.Error(), \"error checking token status\") {\n    time.Sleep(backoff)\n    return callAPI() // transient DB failure; retry\n}\nreturn resp, err","preventionTips":["Add DB health/readiness checks before serving API traffic","Size the connection pool for API-token request volume","Keep migrations current so token queries never hit schema errors","Distinguish NotFound (revoke/reissue) from infrastructure errors in client retry logic"],"tags":["database","authentication","api-token"],"backgroundTag":"database-unavailable","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}