{"record":{"id":"25a9f33c67b35498","repo":"hcengineering/platform","slug":"accountnotfound-25a9f3","errorCode":"AccountNotFound","errorMessage":"AccountNotFound","messagePattern":"AccountNotFound","errorType":"exception","errorClass":"PlatformError","httpStatus":null,"severity":"error","filePath":"server/account/src/serviceOperations.ts","lineNumber":245,"sourceCode":"  branding: Branding | null,\n  token: string,\n  params: {\n    socialKey: string\n    targetRole: AccountRole\n  }\n): Promise<void> {\n  const { socialKey, targetRole } = params\n\n  if (socialKey == null || socialKey === '' || targetRole == null || !assignableRoles.includes(targetRole)) {\n    throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {}))\n  }\n\n  const { extra } = decodeTokenVerbose(ctx, token)\n  verifyAllowedServices(['workspace', 'tool'], extra)\n\n  const socialId = await getSocialIdByKey(db, socialKey.toLowerCase() as PersonId)\n  if (socialId == null) {\n    throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, {}))\n  }\n\n  await updateWorkspaceRole(ctx, db, branding, token, { targetAccount: socialId.personUuid as AccountUuid, targetRole })\n}\n\n/**\n * Retrieves one workspace for which there are things to process.\n *\n * Workspace is provided for 30seconds. This timeout is reset\n * on every progress update.\n * If no progress is reported for the workspace during this time,\n * it will become available again to be processed by another executor.\n */\nexport async function getPendingWorkspace (\n  ctx: MeasureContext,\n  db: AccountDB,\n  branding: Branding | null,\n  token: string,","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/server/account/src/serviceOperations.ts#L227-L263","documentation":"AccountNotFound is thrown by updateWorkspaceRoleBySocialKey when the provided socialKey does not resolve to any social account in the database. The service looks up getSocialIdByKey with the lowercased socialKey, and if no row matches, it cannot determine the target account for the role update, so it aborts with this PlatformError status. It indicates the caller supplied an identifier for an account that does not exist (or was never linked).","triggerScenarios":"Calling updateWorkspaceRoleBySocialKey with a socialKey string that has no corresponding social_id row in the account database: the key is wrong/typo'd, the key was never registered, the social account was deleted, or the key case differed pre-normalization (the function lowercases it, so mixed-case stored keys will not match).","commonSituations":"Workspace provisioning flows where a tool service passes a social key obtained from an external SSO provider before that account finished linking in Huly; stale keys cached on the client after account removal; passing an email or external user id instead of the actual social key; environment mismatch (key exists in prod DB but not in the staging DB being called).","solutions":["Verify the socialKey value is the exact key stored in the account's social_id table (query by key = lowercased value) before calling the API.","Ensure the social account is actually registered/linked via the signup/link flow before attempting a role update.","Check you are pointing at the correct database/environment (staging vs prod) where the account exists.","Handle the PlatformError with status AccountNotFound in the caller and surface a 'create account first' flow instead of retrying."],"exampleFix":"// before\nawait accountClient.updateWorkspaceRoleBySocialKey(ctx, token, socialKey, role)\n\n// after\nconst normalizedKey = socialKey.trim().toLowerCase()\nconst existing = await findSocialIdByKey(db, normalizedKey)\nif (existing == null) {\n  await accountClient.signupAndLinkSocial(ctx, token, normalizedKey) // ensure account exists first\n}\nawait accountClient.updateWorkspaceRoleBySocialKey(ctx, token, normalizedKey, role)","handlingStrategy":"validation","validationCode":"// Ensure the social key is normalized and resolvable before the call\nconst normalizedKey = socialKey.trim().toLowerCase()\nif (!normalizedKey) throw new Error('socialKey is required')\nconst socialId = await findSocialIdByKey(db, normalizedKey)\nif (socialId == null) throw new Error(`No account linked to socialKey ${normalizedKey}; register/link the account first`)","typeGuard":"function hasSocialAccount(v: SocialId | null | undefined): v is SocialId {\n  return v != null && typeof v.personUuid === 'string'\n}","tryCatchPattern":"try {\n  await updateWorkspaceRoleBySocialKey(ctx, db, branding, token, socialKey, targetRole)\n} catch (err) {\n  if (err instanceof PlatformError && err.status.code === platform.status.AccountNotFound) {\n    // prompt user to sign up / link social account\n    return\n  }\n  throw err\n}","preventionTips":["Always lowercase/trim the socialKey before use, matching the service's normalization.","Confirm the account completed social signup/link before issuing role updates.","Keep a registry check (social_id table lookup) in the calling flow.","Verify environment (staging vs prod) matches where the account was created."],"tags":["account","authorization","social-login","not-found"],"backgroundTag":"account-not-found","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}