{"record":{"id":"2ab366b4db8cbb3f","repo":"yikart/AiToEarn","slug":"accountnotfound-2ab366","errorCode":"AccountNotFound","errorMessage":"AccountNotFound","messagePattern":"AccountNotFound","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/platforms.service.ts","lineNumber":151,"sourceCode":"    return {\n      field: source.field,\n      label: source.label,\n      description: source.description,\n      valueType: source.valueType,\n      requiresAccount: source.requiresAccount,\n      filterSchema: source.filterSchema\n        ? z.toJSONSchema(source.filterSchema, { ...zodToJsonSchemaOptions, io: 'input' }) as PublishOptionJsonSchemaView\n        : undefined,\n      createSchema: source.createSchema\n        ? z.toJSONSchema(source.createSchema, { ...zodToJsonSchemaOptions, io: 'input' }) as PublishOptionJsonSchemaView\n        : undefined,\n    }\n  }\n\n  private async getAccountOptionContext(userId: string, accountId: string, field: string) {\n    const account = await this.accountRepository.getByIdAndUserId(accountId, userId)\n    if (!account) {\n      throw new AppException(ResponseCode.AccountNotFound)\n    }\n    if (account.relayAccountRef) {\n      throw new RelayAccountException(account.relayAccountRef, accountId)\n    }\n\n    const provider = this.registry.getPublishOptions(account.type)\n    if (!provider) {\n      throw new AppException(ResponseCode.ChannelPlatformOperationNotSupported, {\n        platform: account.type,\n        field,\n      })\n    }\n\n    const source = provider.listSources().find(item => item.field === field)\n    if (!source) {\n      throw new AppException(ResponseCode.ChannelPlatformOperationNotSupported, {\n        platform: account.type,\n        field,","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/platforms.service.ts#L133-L169","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Refresh the account list (GET accounts for the current user) and use a fresh accountId before retrying.","Verify the accountId belongs to the authenticated user; never use ids from other users or environments.","Handle this code by removing the stale account from local state and prompting re-selection.","If the account should exist, check whether it was deleted by a cleanup job or disconnect flow and re-authenticate the channel."],"exampleFix":"// before\nawait api.post(`/accounts/${staleAccountId}/options/${field}/values`, data)\n// after\nconst accounts = await api.get('/accounts')\nconst account = accounts.find(a => a.id === staleAccountId)\nif (!account) {\n  await refreshAccountSelection()\n  return\n}\nawait api.post(`/accounts/${account.id}/options/${field}/values`, data)","handlingStrategy":"try-catch","validationCode":"const accounts = await api.get('/accounts')\nif (!accounts.some(a => a.id === accountId)) {\n  await promptAccountReselection()\n  return\n}","typeGuard":"function ownsAccount(accounts: Account[], accountId: string): boolean {\n  return accounts.some(a => a.id === accountId)\n}","tryCatchPattern":"try {\n  return await api.createAccountValue(accountId, field, data)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.AccountNotFound) {\n    await refreshAccounts()\n    throw new RetryableError('Account list was stale; refreshed')\n  }\n  throw e\n}","preventionTips":["Always derive accountId from a fresh list of the current user's accounts.","Never hardcode or copy account ids between users/environments.","Clear cached account selections after disconnect/delete operations.","Treat AccountNotFound as 'refresh and re-select', not a retryable server fault."],"tags":["account","not-found","authorization","rest"],"backgroundTag":"resource-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}