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
- Call getIntegration first and create the integration via createIntegration when it is missing (upsert pattern).
- Verify the exact socialId/kind/workspaceUuid triple matches the one used at creation.
- Check you are connected to the intended account-service database/environment.
- 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
- Always fetch the integration first and upsert
- Freeze the socialId/kind/workspaceUuid triple per integration in app state
- Verify environment/DB consistency between creation and update code paths
- Log the full key on failure to spot mismatched workspaceUuid
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
- Integration not found: ${JSON.stringify(integrationKey)}
- core.status.ObjectNotFound
- platform.status.ResourceNotFound
- Email is not defined in integration
- Lead not found, _id: ${ref}
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/0533b74865969231.
Report an issue: GitHub.