hcengineering/platform · error · PlatformError

IntegrationAlreadyExists

IntegrationAlreadyExists

Error message

IntegrationAlreadyExists

What it means

PlatformStatus IntegrationAlreadyExists is thrown by the account service's createIntegration when an integration with the exact (socialId, kind, workspaceUuid) key already exists in the integration collection. findExistingIntegration is consulted first, and any non-null hit means the caller is attempting to insert a duplicate integration. It is a logical/ pre-condition violation of the unique key, not a transport or auth failure.

Source

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

  if (socialId != null) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.SocialIdNotFound, { _id: personId }))
  }

  await db.socialId.update({ _id: personId }, { displayValue })
}

export async function createIntegration (
  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.IntegrationAlreadyExists, {}))
  }

  const { socialId, kind, workspaceUuid, data } = params
  const social = await db.socialId.findOne({ _id: socialId })

  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

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Check for the existing integration first (via getIntegration or a prior listIntegrations) and call updateIntegration instead when one exists.
  2. Catch PlatformError with status IntegrationAlreadyExists and treat it as idempotent success if the stored data matches the request.
  3. Delete the stale integration via deleteIntegration (or use upsert-style logic client-side) before recreating it.
  4. Ensure the client generates distinct kind values when the same socialId is intentionally used for multiple integrations of different types.

Example fix

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

Strategy: try-catch

Validate before calling

const existing = await client.getIntegration(ctx, token, { socialId, kind, workspaceUuid })
if (existing != null) throw new Error('integration already exists; call updateIntegration instead')

Type guard

function canCreate(p: Integration): boolean {
  return p.kind != null && p.kind !== '' && p.socialId != null && p.socialId !== '' && p.workspaceUuid !== undefined
}

Try / catch

try {
  await client.createIntegration(ctx, token, params)
} catch (err) {
  if (err instanceof PlatformError && err.status.code === platform.status.IntegrationAlreadyExists) {
    return // idempotent: already present
  }
  throw err
}

Prevention

When it happens

Trigger: Calling createIntegration with params whose (socialId, kind, workspaceUuid) tuple matches a row already inserted by a previous createIntegration call (e.g. re-running an OAuth connect flow for the same GitHub/Gmail account in the same workspace).

Common situations: Retry logic that blindly re-invokes createIntegration after a timeout; client double-submit of the connect dialog; re-connecting a social account that was already integrated rather than calling updateIntegration to change its data.

Related errors


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