yikart/AiToEarn · warning · AppException

ResponseCode.ChannelAuthSelectionRequired

ResponseCode.ChannelAuthSelectionRequired

Error message

ChannelAuthSelectionRequired

What it means

Thrown in AuthService.saveSelectedAccountsForUser when the submitted selectedAccounts array is empty. Persisting the user's chosen second-level accounts requires at least one account identity ({ platformUid, account? }); an empty submission means nothing was selected.

Source

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

    allowReassign?: boolean
  }): Promise<{ accountIds: string[], accounts: ConnectedSelectableAccount[] }> {
    const result = await this.saveSelectedAccountsForUser(input)
    await Promise.all(result.accounts.map(account => this.emitAccountConnected(input.userId, account.accountId, account.platform, input.source)))
    return result
  }

  @Transactional()
  private async saveSelectedAccountsForUser(input: {
    userId: string
    platform: AccountType
    selectableAccounts: PlatformSelectableAccount[]
    selectedAccounts: SelectedAccountIdentity[]
    groupId?: string
    source: string
    allowReassign?: boolean
  }): Promise<{ accountIds: string[], accounts: ConnectedSelectableAccount[] }> {
    if (input.selectedAccounts.length === 0) {
      throw new AppException(ResponseCode.ChannelAuthSelectionRequired)
    }

    const keyOf = (account: SelectedAccountIdentity) => `${account.platformUid}\u0000${account.account ?? ''}`
    const selectedAccounts = Array.from(
      new Map(input.selectedAccounts.map(account => [keyOf(account), account])).values(),
    )
    const selectableAccounts = new Map(
      input.selectableAccounts.map(account => [keyOf(account), account]),
    )
    const unknownAccount = selectedAccounts.find(account => !selectableAccounts.has(keyOf(account)))
    if (unknownAccount) {
      throw new AppException(ResponseCode.ChannelAuthSelectedAccountUnavailable)
    }

    const groupId = await this.resolveGroupId(input.userId, input.groupId)
    const accountIds: string[] = []
    const accounts: ConnectedSelectableAccount[] = []

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Enforce at least one selection in the UI (disable submit until a checkbox is ticked) and validate client-side before POSTing.
  2. Reject empty arrays at the DTO boundary with a Zod min-length constraint so callers get a clear 400-style message.
  3. Check the frontend form serialization — ensure the accounts field is populated from the selection checkboxes.
  4. If the user legitimately wants to select none, cancel the flow instead of submitting an empty selection.

Example fix

// before: DTO allows empty array
accounts: z.array(selectedAccountSchema)

// after: require at least one selection
accounts: z.array(selectedAccountSchema).min(1)
Defensive patterns

Strategy: validation

Validate before calling

function canSubmitSelection(selected: SelectedAccountIdentity[]): boolean {
  return Array.isArray(selected) && selected.length > 0
}
if (!canSubmitSelection(collectedSelections)) {
  alert('Select at least one account')
  return
}

Type guard

function hasSelections(v: unknown): v is SelectedAccountIdentity[] {
  return Array.isArray(v) && v.length > 0 && v.every(i => typeof (i as any).platformUid === 'string')
}

Try / catch

try {
  await submitSelections(selected)
}
catch (e) {
  if (getErrorCode(e) === ResponseCode.ChannelAuthSelectionRequired) {
    showError('Please select at least one account before continuing')
  }
}

Prevention

When it happens

Trigger: saveSelectedAccountsForUser (via connectSelectableAccounts / connectSelectedAccountsForUser, e.g. POST /accounts/auth/selections) with body.accounts = [] — an empty selection form, a frontend bug sending no accounts, or an API caller omitting the accounts list.

Common situations: User submits the account-selection page without ticking any checkbox; frontend not mapping the checkbox values into the request body; DTO accepting an empty array because the schema only validates item shape, not min length; scripted calls to the endpoint with an empty payload.

Related errors


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