{"record":{"id":"aeed0781e0f9bc2c","repo":"yikart/AiToEarn","slug":"relayauthexception","errorCode":null,"errorMessage":"RelayAuthException","messagePattern":"RelayAuthException","errorType":"exception","errorClass":"RelayAuthException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/auth/auth.service.ts","lineNumber":433,"sourceCode":"        type: identity.platform,\n        uid: identity.platformUid,\n        account: accountIdentity,\n      })\n      if (account?.userId) {\n        owners.add(account.userId)\n      }\n    }\n\n    return Array.from(owners)\n  }\n\n  async getAuthSessionResult(\n    userId: string,\n    platform: AccountType | undefined,\n    sessionId: string,\n  ): Promise<AuthSessionResult> {\n    if (this.relayClientService?.enabled) {\n      throw new RelayAuthException()\n    }\n    const session = await this.redis.getChannelAuthSession<AuthSession>(sessionId)\n    if (!session || session.userId !== userId) {\n      throw new AppException(ResponseCode.ChannelAuthSessionInvalid)\n    }\n    if (this.isSessionExpired(session)) {\n      throw new AppException(ResponseCode.ChannelAuthSessionInvalid)\n    }\n    if (platform && session.platform !== platform) {\n      throw new AppException(ResponseCode.ChannelAuthPlatformMismatch)\n    }\n    const expiresAt = this.getSessionExpiresAt(session)\n\n    return {\n      sessionId: session.id,\n      status: session.status,\n      requiresSelection: session.status === ChannelAuthSessionStatus.Pending\n        && Boolean(session.selectableAccounts?.length),","sourceCodeStart":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/auth/auth.service.ts#L415-L451","documentation":"getAuthSessionResult refuses to serve auth session results when the relay client service is enabled; RelayAuthException signals that session polling must go through the Relay flow instead of this local Redis-backed path. It enforces the environment separation between Relay mode and direct channel auth.","triggerScenarios":"Calling getAuthSessionResult (direct REST polling of an auth session) while this server instance has RelayAuthClientService enabled (RELAY mode configured).","commonSituations":"Deployment misconfiguration: server started with Relay enabled but an old client/integration still polls the direct session endpoint; mixing China/international or relay/direct environments; tests written against direct auth running in a relay-enabled environment.","solutions":["Use the Relay endpoint/SDK to obtain auth results instead of the direct session API","Disable the relay client in environments that rely on direct channel auth polling","Point the client at the correct environment (aitoearn.cn vs aitoearn.ai) matching the key type"],"exampleFix":"// before\nconst result = await api.getAuthSessionResult(userId, platform, sessionId) // 409/500 RelayAuthException\n// after\nconst result = relayEnabled\n  ? await relayClient.getAuthResult(sessionId)\n  : await api.getAuthSessionResult(userId, platform, sessionId)","handlingStrategy":"fallback","validationCode":"const useRelay = relayClientService?.enabled === true\nif (useRelay) { /* route to relay flow instead of direct session API */ }","typeGuard":"function isRelayAuthException(e): e is RelayAuthException { return e?.name === 'RelayAuthException' }","tryCatchPattern":"try {\n  return await api.getAuthSessionResult(userId, platform, sessionId)\n} catch (e) {\n  if (isRelayAuthException(e)) return relayClient.getAuthResult(sessionId)\n  throw e\n}","preventionTips":["Align client auth path with server relay configuration","Distinguish aitoearn.cn vs aitoearn.ai environments per API key","Document relay-mode constraints for integrators"],"tags":["relay","config","channel-auth"],"backgroundTag":"relay-mode-not-supported","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}