yikart/AiToEarn · error · AppException

ChannelAuthPlatformUidMissing

ChannelAuthPlatformUidMissing

Error message

ChannelAuthPlatformUidMissing

What it means

getProfile needs the platform's openId (platformUid) to call WeChat's user info endpoint. When input.platformUid is missing, AppException(ResponseCode.ChannelAuthPlatformUidMissing) is thrown, since the Official Account user-info API cannot be queried without the openid.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/wechat/wechat-official/wechat-official-auth.provider.ts:90

    return {
      accessToken: result.accessToken,
      refreshToken: result.refreshToken,
      expiresAt: new Date(Date.now() + result.expiresIn * 1000),
      scope: result.scope,
    }
  }

  async revoke(_input: RevokeCredentialInput): Promise<void> {
    // WeChat Official Account OAuth does not support server-side token revocation.
    // Tokens expire naturally (2 hours for access, 30 days for refresh).
    this.logger.log('WeChat Official Account tokens expire naturally; no revocation needed')
  }

  async getProfile(input: CredentialContext): Promise<PlatformAccountProfile> {
    const openId = input.platformUid
    if (!openId) {
      throw new AppException(ResponseCode.ChannelAuthPlatformUidMissing)
    }

    const userInfo = await this.wechatService.getOfficialUserInfo(
      input.accessToken,
      openId,
    )

    return {
      platformUid: userInfo.openId,
      displayName: userInfo.nickname,
      avatarUrl: userInfo.avatarUrl,
      raw: {
        unionId: userInfo.unionId,
      },
    }
  }
}

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Re-run the OAuth flow so openid is captured and stored as platformUid
  2. Backfill platformUid from WeChat's /cgi-bin/user/info or OAuth userinfo response for existing credentials
  3. Guard call sites: skip getProfile when platformUid is absent and schedule re-auth instead
  4. Verify the credential context builder always maps WeChat openid into platformUid

Example fix

// before
const profile = await authProvider.getProfile({ accessToken })
// after
if (!credential.platformUid) {
  await startReauthFlow(channelId)
}
const profile = await authProvider.getProfile(credential)
Defensive patterns

Strategy: validation

Validate before calling

if (!credential.platformUid) {
  scheduleReauth(channelId)
} else {
  await authProvider.getProfile(credential)
}

Type guard

function hasPlatformUid(c: unknown): c is { platformUid: string } {
  return typeof (c as any)?.platformUid === 'string' && (c as any).platformUid.length > 0
}

Try / catch

try {
  const profile = await authProvider.getProfile(ctx)
} catch (e) {
  if (e?.code === 'ChannelAuthPlatformUidMissing') {
    await startReauthFlow(ctx.channelId)
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling getProfile with a CredentialContext built from OAuth flows that did not capture openid, or from credential records where platformUid was never saved.

Common situations: Channels connected via a flow that only stored the access token, older credentials predating platformUid persistence, copying credentials between accounts losing the uid mapping.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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