#15587·activepieces

[BUG] Connect Git returns a generic error when the SSH connection cannot be established

Author: majewskibartoszCreated Sep 16, 2026Updated Sep 17, 2026
Labels🐛 bug🏢 area/management🛟 support

Problem

Project Settings → Environment → Connect Git. When the server cannot open an SSH connection to the git host (outbound port 22 blocked at the network level, packets dropped rather than rejected), the dialog shows the generic "An unexpected error occurred. Please try again in a moment." Nothing names the connection failure, in the UI or in the logs.

Reachable remote with no access is handled correctly: 400 INVALID_GIT_CREDENTIALS, dialog renders "Invalid git credentials, please check the credentials, Could not read from remote repository." Verified by running validateConnection directly.

Reported by a self-hosted deployment. Root cause on their side was a closed outbound 22, which they fixed themselves. The product gap is that nothing told them that.

Ref: Pylon 6000

Root cause

packages/server/api/src/app/ee/projects/project-release/git-sync/git-helper.ts:95

typescript
.env('GIT_SSH_COMMAND', `ssh -i ${keyPath} -o StrictHostKeyChecking=no`)

No ConnectTimeout, no BatchMode. A dropped TCP connect leaves git pull hanging for the OS connect timeout, past any proxy idle timeout, so the browser gets a gateway error rather than the API's 400. packages/web/src/features/project-releases/components/connect-git-dialog.tsx:78-86 falls back to the generic string for any response code that is not INVALID_GIT_CREDENTIALS.

Unverified: the exact status the reporter's proxy returned. Not captured before they fixed the firewall.

Secondary defect: cleanup in finally destroys the real error

git-helper.ts:154-155

typescript
finally {
    await fs.rmdir(tmpFolder, { recursive: true })
    await fs.unlink(keyPath)
}

Unguarded. Any failure at or before createOrGetSshKeyPath (line 142) means the key file was never written, so fs.unlink throws ENOENT and that replaces the in-flight INVALID_GIT_CREDENTIALS on the way out: raw 500 in the response, unlink ENOENT in the logs, original cause gone. Reproduced.

fs.rmdir(..., { recursive: true }) is also Node DEP0147.

Fix

  1. line 95: ssh -i ${keyPath} -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=10. Fails fast, so the reason reaches the user as a 400. BatchMode also stops a passphrase-protected key hanging on a prompt.
  2. lines 154-155: fs.rm(tmpFolder, { recursive: true, force: true }) and fs.rm(keyPath, { force: true }).

Notes

validateConnection returns early when AP_ENVIRONMENT=TESTING, so no integration test covers this path.

Source: activepieces/activepieces