yikart/AiToEarn · error · AppException

AccountNotFound

AccountNotFound

Error message

AccountNotFound

What it means

getAccountOptionContext loads the account with getByIdAndUserId(accountId, userId) to scope option-field operations to the caller's own account. If no account matches both the id and the user id (nonexistent, deleted, or owned by someone else), it throws AccountNotFound. This is deliberately indistinguishable between 'not exists' and 'not yours'.

Source

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

    return {
      field: source.field,
      label: source.label,
      description: source.description,
      valueType: source.valueType,
      requiresAccount: source.requiresAccount,
      filterSchema: source.filterSchema
        ? z.toJSONSchema(source.filterSchema, { ...zodToJsonSchemaOptions, io: 'input' }) as PublishOptionJsonSchemaView
        : undefined,
      createSchema: source.createSchema
        ? z.toJSONSchema(source.createSchema, { ...zodToJsonSchemaOptions, io: 'input' }) as PublishOptionJsonSchemaView
        : undefined,
    }
  }

  private async getAccountOptionContext(userId: string, accountId: string, field: string) {
    const account = await this.accountRepository.getByIdAndUserId(accountId, userId)
    if (!account) {
      throw new AppException(ResponseCode.AccountNotFound)
    }
    if (account.relayAccountRef) {
      throw new RelayAccountException(account.relayAccountRef, accountId)
    }

    const provider = this.registry.getPublishOptions(account.type)
    if (!provider) {
      throw new AppException(ResponseCode.ChannelPlatformOperationNotSupported, {
        platform: account.type,
        field,
      })
    }

    const source = provider.listSources().find(item => item.field === field)
    if (!source) {
      throw new AppException(ResponseCode.ChannelPlatformOperationNotSupported, {
        platform: account.type,
        field,

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Refresh the account list (GET accounts for the current user) and use a fresh accountId before retrying.
  2. Verify the accountId belongs to the authenticated user; never use ids from other users or environments.
  3. Handle this code by removing the stale account from local state and prompting re-selection.
  4. If the account should exist, check whether it was deleted by a cleanup job or disconnect flow and re-authenticate the channel.

Example fix

// before
await api.post(`/accounts/${staleAccountId}/options/${field}/values`, data)
// after
const accounts = await api.get('/accounts')
const account = accounts.find(a => a.id === staleAccountId)
if (!account) {
  await refreshAccountSelection()
  return
}
await api.post(`/accounts/${account.id}/options/${field}/values`, data)
Defensive patterns

Strategy: try-catch

Validate before calling

const accounts = await api.get('/accounts')
if (!accounts.some(a => a.id === accountId)) {
  await promptAccountReselection()
  return
}

Type guard

function ownsAccount(accounts: Account[], accountId: string): boolean {
  return accounts.some(a => a.id === accountId)
}

Try / catch

try {
  return await api.createAccountValue(accountId, field, data)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.AccountNotFound) {
    await refreshAccounts()
    throw new RetryableError('Account list was stale; refreshed')
  }
  throw e
}

Prevention

When it happens

Trigger: Calling option-related endpoints (createAccountValue, list option sources) with an accountId that does not exist, was deleted, was disconnected, or belongs to a different user — the repository returns null and the code throws.

Common situations: A stale accountId cached in the client after the account was removed/reconnected; copying an accountId from another user/workspace; a test fixture id used in production; race where the account was deleted between listing and the follow-up call.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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