{"record":{"id":"d43b3de355fe6f05","repo":"yikart/AiToEarn","slug":"responsecode-channelauthsessioninvalid-d43b3d","errorCode":"ResponseCode.ChannelAuthSessionInvalid","errorMessage":"ChannelAuthSessionInvalid","messagePattern":"ChannelAuthSessionInvalid","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/auth/auth.service.ts","lineNumber":106,"sourceCode":"\n    await this.redis.saveChannelAuthSession(session.id, session)\n\n    return {\n      url: result.url,\n      sessionId,\n      expiresAt,\n      authInstructions: integration.metadata.authInstructions,\n    }\n  }\n\n  async completeCallback(\n    platform: AccountType,\n    callbackInput: Omit<AuthCallbackInput, 'session'>,\n    sessionId: string,\n  ): Promise<AuthCallbackResult> {\n    const session = await this.redis.getChannelAuthSession<AuthSession>(sessionId)\n    if (!this.isAccountAuthSessionRecord(session)) {\n      throw new AppException(ResponseCode.ChannelAuthSessionInvalid)\n    }\n    if (this.isSessionExpired(session)) {\n      throw new AppException(ResponseCode.ChannelAuthSessionInvalid)\n    }\n    if (session.platform !== platform) {\n      throw new AppException(ResponseCode.ChannelAuthPlatformMismatch)\n    }\n    if (session.status !== ChannelAuthSessionStatus.Pending) {\n      throw new AppException(ResponseCode.ChannelAuthSessionCompleted)\n    }\n\n    const provider = this.registry.getAuth(platform)\n    const credentialResult = await provider.exchangeCode({\n      ...callbackInput,\n      session,\n    })\n\n    const credentialContext = credentialResult.accessToken","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/auth/auth.service.ts#L88-L124","documentation":"Thrown in AuthService.completeCallback when the Redis record for the given session ID is not a valid account-auth session (isAccountAuthSessionRecord fails or the key is missing). The stored AuthSession is the only proof that this callback belongs to a legitimately started authorization flow.","triggerScenarios":"completeCallback is called with a sessionId that: was never created (bogus state), was deleted by Redis eviction/TTL, is a different session type (not AccountAuth flow), or the Redis database was flushed/restarted without persistence.","commonSituations":"Redis restart or eviction losing the session; reusing an old state value after the flow was restarted; switching Redis DBs/instances between environments (e.g. staging vs prod URL); TTL expiry misread as 'invalid' by the developer.","solutions":["Restart the channel auth flow to generate a fresh session and use its state/sessionId for the callback.","Check Redis connectivity and that the instance holding the session is the one the server reads (verify REDIS config/env per environment).","Increase the session TTL if users take long between starting auth and completing the provider login.","Confirm the callback passes the exact state echoed by the provider — no truncation or re-encoding of the session ID."],"exampleFix":"// before: retrying a stale callback after Redis restart\nawait authService.completeCallback(platform, callbackInput, oldSessionId)\n\n// after: detect and restart the flow\ntry {\n  await authService.completeCallback(platform, callbackInput, sessionId)\n}\ncatch (e) {\n  if (getErrorCode(e) === ResponseCode.ChannelAuthSessionInvalid) {\n    const fresh = await authService.generateAuthUrl(...) // new session + state\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await authService.completeCallback(platform, callbackInput, sessionId)\n}\ncatch (e) {\n  if (getErrorCode(e) === ResponseCode.ChannelAuthSessionInvalid) {\n    await restartAuthFlow(userId, platform) // fresh session + state\n  }\n}","preventionTips":["Use a persistent Redis (AOF/RDB) for auth sessions","Pin one Redis instance per environment and verify env config","Never reuse state values across flows","Monitor Redis eviction/maxmemory settings"],"tags":["oauth","redis","session","state"],"backgroundTag":"oauth-session-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}