yikart/AiToEarn · error · AppException

ResponseCode.ChannelAuthSessionInvalid

ResponseCode.ChannelAuthSessionInvalid

Error message

ChannelAuthSessionInvalid

What it means

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.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/auth/auth.service.ts:106

    await this.redis.saveChannelAuthSession(session.id, session)

    return {
      url: result.url,
      sessionId,
      expiresAt,
      authInstructions: integration.metadata.authInstructions,
    }
  }

  async completeCallback(
    platform: AccountType,
    callbackInput: Omit<AuthCallbackInput, 'session'>,
    sessionId: string,
  ): Promise<AuthCallbackResult> {
    const session = await this.redis.getChannelAuthSession<AuthSession>(sessionId)
    if (!this.isAccountAuthSessionRecord(session)) {
      throw new AppException(ResponseCode.ChannelAuthSessionInvalid)
    }
    if (this.isSessionExpired(session)) {
      throw new AppException(ResponseCode.ChannelAuthSessionInvalid)
    }
    if (session.platform !== platform) {
      throw new AppException(ResponseCode.ChannelAuthPlatformMismatch)
    }
    if (session.status !== ChannelAuthSessionStatus.Pending) {
      throw new AppException(ResponseCode.ChannelAuthSessionCompleted)
    }

    const provider = this.registry.getAuth(platform)
    const credentialResult = await provider.exchangeCode({
      ...callbackInput,
      session,
    })

    const credentialContext = credentialResult.accessToken

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Restart the channel auth flow to generate a fresh session and use its state/sessionId for the callback.
  2. Check Redis connectivity and that the instance holding the session is the one the server reads (verify REDIS config/env per environment).
  3. Increase the session TTL if users take long between starting auth and completing the provider login.
  4. Confirm the callback passes the exact state echoed by the provider — no truncation or re-encoding of the session ID.

Example fix

// before: retrying a stale callback after Redis restart
await authService.completeCallback(platform, callbackInput, oldSessionId)

// after: detect and restart the flow
try {
  await authService.completeCallback(platform, callbackInput, sessionId)
}
catch (e) {
  if (getErrorCode(e) === ResponseCode.ChannelAuthSessionInvalid) {
    const fresh = await authService.generateAuthUrl(...) // new session + state
  }
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await authService.completeCallback(platform, callbackInput, sessionId)
}
catch (e) {
  if (getErrorCode(e) === ResponseCode.ChannelAuthSessionInvalid) {
    await restartAuthFlow(userId, platform) // fresh session + state
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/d43b3de355fe6f05. Report an issue: GitHub.