diff --git a/connectors/src/connectors/slack/index.ts b/connectors/src/connectors/slack/index.ts index 9ab66f5c04d3..5c970518ea0e 100644 --- a/connectors/src/connectors/slack/index.ts +++ b/connectors/src/connectors/slack/index.ts @@ -17,7 +17,7 @@ import { getSlackClient, } from "@connectors/connectors/slack/lib/slack_client"; import { launchSlackSyncWorkflow } from "@connectors/connectors/slack/temporal/client.js"; -import { ExternalOauthTokenError } from "@connectors/lib/error"; +import { ExternalOauthTokenError, NangoError } from "@connectors/lib/error"; import { Connector, sequelize_conn } from "@connectors/lib/models"; import { SlackChannel, @@ -248,9 +248,8 @@ export async function uninstallSlack(nangoConnectionId: string) { throw new Error("SLACK_CLIENT_SECRET is not defined"); } - const slackAccessToken = await getSlackAccessToken(nangoConnectionId); - try { + const slackAccessToken = await getSlackAccessToken(nangoConnectionId); const slackClient = await getSlackClient(slackAccessToken); await slackClient.auth.test(); const deleteRes = await slackClient.apps.uninstall({ @@ -265,7 +264,16 @@ export async function uninstallSlack(nangoConnectionId: string) { ); } } catch (e) { - if (e instanceof ExternalOauthTokenError) { + if (e instanceof NangoError && e.type === "unknown_connection") { + logger.info( + { + nangoConnectionId, + error: `Nango error: unknown connection: ${e.message}`, + }, + "Unknown nango connection, skipping uninstallation of the Slack app" + ); + return new Ok(undefined); + } else if (e instanceof ExternalOauthTokenError) { logger.info( { nangoConnectionId, diff --git a/connectors/src/lib/error.ts b/connectors/src/lib/error.ts index 9547d2910bad..b348363014f7 100644 --- a/connectors/src/lib/error.ts +++ b/connectors/src/lib/error.ts @@ -63,6 +63,19 @@ export class ExternalOauthTokenError extends Error { } } +export const NANGO_ERROR_TYPES = ["unknown_connection"]; +export type NangoErrorType = (typeof NANGO_ERROR_TYPES)[number]; +export class NangoError extends Error { + readonly type: NangoErrorType; + + constructor(type: NangoErrorType, readonly innerError?: Error) { + super(innerError?.message); + this.name = "NangoError"; + this.type = type; + this.innerError = innerError; + } +} + export function isNotFoundError(err: unknown): err is NotFoundError { return err instanceof HTTPError && err.statusCode === 404; } diff --git a/connectors/src/lib/nango_client.ts b/connectors/src/lib/nango_client.ts index fbeb5acacda8..a36e9e50009c 100644 --- a/connectors/src/lib/nango_client.ts +++ b/connectors/src/lib/nango_client.ts @@ -2,10 +2,13 @@ import { Nango } from "@nangohq/node"; import axios from "axios"; import type { WorkflowError } from "@connectors/lib/error"; -import { ExternalOauthTokenError } from "@connectors/lib/error"; - -import type { Result } from "./result"; -import { Err, Ok } from "./result"; +import { + ExternalOauthTokenError, + NANGO_ERROR_TYPES, + NangoError, +} from "@connectors/lib/error"; +import type { Result } from "@connectors/lib/result"; +import { Err, Ok } from "@connectors/lib/result"; const { NANGO_SECRET_KEY } = process.env; @@ -35,6 +38,10 @@ class CustomNango extends Nango { ) { throw new ExternalOauthTokenError(); } + const errorType = e.response.data.type; + if (NANGO_ERROR_TYPES.includes(errorType)) { + throw new NangoError(errorType, e); + } } } if (e.status === 520 && e.code === "ERR_BAD_RESPONSE") {