hcengineering/platform · error · PlatformError

IntegrationNotFound

IntegrationNotFound

Error message

IntegrationNotFound

What it means

IntegrationNotFound is thrown by updateIntegration when findExistingIntegration returns null — no integration exists for the given (socialId, kind, workspaceUuid) key (or the caller is not allowed to see it). The service refuses to update a non-existent record rather than silently upserting. Before reaching this check, findExistingIntegration also validates params and ownership, so a null can follow a failed ownership path only if Forbidden/SocialIdNotFound were not already raised.

Source

Thrown at server/account/src/serviceOperations.ts:692

  if (social?.personUuid === readOnlyGuestAccountUuid) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
  }

  await db.integration.insertOne({ socialId, kind, workspaceUuid, data })
}

export async function updateIntegration (
  ctx: MeasureContext,
  db: AccountDB,
  branding: Branding | null,
  token: string,
  params: Integration
): Promise<void> {
  const { extra, account } = decodeTokenVerbose(ctx, token)
  // it checks params and throws BadRequest if params are invalid
  const existing = await findExistingIntegration(account, db, params, extra)
  if (existing == null) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.IntegrationNotFound, {}))
  }

  const { socialId, kind, workspaceUuid, data } = params
  await db.integration.update({ socialId, kind, workspaceUuid }, { data })
}

export async function deleteIntegration (
  ctx: MeasureContext,
  db: AccountDB,
  branding: Branding | null,
  token: string,
  params: IntegrationKey
): Promise<void> {
  const { extra, account } = decodeTokenVerbose(ctx, token)
  // it checks params and throws BadRequest if params are invalid
  const existing = await findExistingIntegration(account, db, params, extra)
  if (existing == null) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.IntegrationNotFound, {}))

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Call getIntegration first and create the integration via createIntegration when it is missing (upsert pattern).
  2. Verify the exact socialId/kind/workspaceUuid triple matches the one used at creation.
  3. Check you are connected to the intended account-service database/environment.
  4. Confirm the integration was not deleted by a concurrent process or another team member.

Example fix

// before
await client.updateIntegration(ctx, token, { socialId, kind: 'gmail', workspaceUuid, data })
// after
const existing = await client.getIntegration(ctx, token, { socialId, kind: 'gmail', workspaceUuid })
if (existing == null) {
  await client.createIntegration(ctx, token, { socialId, kind: 'gmail', workspaceUuid, data })
} else {
  await client.updateIntegration(ctx, token, { socialId, kind: 'gmail', workspaceUuid, data })
}
Defensive patterns

Strategy: validation

Validate before calling

const existing = await client.getIntegration(ctx, token, { socialId, kind, workspaceUuid })
if (existing == null) {
  await client.createIntegration(ctx, token, { socialId, kind, workspaceUuid, data })
}

Type guard

function canUpdateKey(p: Integration): p is Integration & { workspaceUuid: string } {
  return p.kind != null && p.kind !== '' && p.socialId != null && p.socialId !== '' && p.workspaceUuid !== undefined
}

Try / catch

try {
  await client.updateIntegration(ctx, token, params)
} catch (err) {
  if (err instanceof PlatformError && err.status.code === platform.status.IntegrationNotFound) {
    await client.createIntegration(ctx, token, params) // upsert fallback
    return
  }
  throw err
}

Prevention

When it happens

Trigger: Calling updateIntegration with a key tuple that was never created, was already deleted via deleteIntegration, or with a workspaceUuid that differs from the one used at creation time.

Common situations: Environment/config drift where the client points at a different DB or workspace; re-running a setup script against a fresh database; changing workspaceUuid casing/format after migration; racing with a concurrent deleteIntegration.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/0533b74865969231. Report an issue: GitHub.