paperclipai/paperclip · error
Managed GitHub connection is unavailable
Error message
Managed GitHub connection is unavailable
What it means
During git credential resolution, Paperclip checks the managed GitHub identity first. If a managed GitHub connection is configured (selected as the identity source) but a usable credential cannot be produced, `resolveManagedGitHubCredential` returns `configured: true` with an `error` message instead of a credential. `resolveCredential` then fails closed and throws this error rather than silently falling back to legacy company secrets or the server's GITHUB_TOKEN/GH_TOKEN environment variables.
Source
Thrown at server/src/services/git-credentials.ts:238
secrets?: GitCredentialSecretsDeps;
env?: NodeJS.ProcessEnv;
secretNames?: readonly string[];
},
): GitRemoteAuthProvider {
const secrets: GitCredentialSecretsDeps = deps?.secrets ?? secretService(db);
const env = deps?.env ?? process.env;
const secretNames = deps?.secretNames ?? DEFAULT_GITHUB_TOKEN_SECRET_NAMES;
let credentialPromise: Promise<GitCredential | null> | null = null;
const resolveCredential = async (): Promise<GitCredential | null> => {
// Unit callers historically pass a null DB through the typed test seam. Production
// always supplies a real DB and therefore always checks managed identities before
// considering legacy secrets or process environment credentials.
const managed = db
? await resolveManagedGitHubCredential(db, secrets, companyId, context ?? {})
: { configured: false as const };
if (managed.configured) {
if (!managed.credential) throw new Error(managed.error ?? "Managed GitHub connection is unavailable");
return managed.credential;
}
for (const secretName of secretNames) {
const secret = await Promise.resolve(secrets.getByName(companyId, secretName)).catch(() => null);
if (!secret) continue;
// A resolution failure (inactive secret, provider outage) records its own failure audit
// event; fall through to the next source instead of failing the whole git operation here.
const token = await secrets
.resolveSecretValue(companyId, secret.id, "latest", {
accessContext: {
consumerType: "system",
consumerId: "workspace-git-credential",
actorType: "system",
issueId: context?.issueId ?? null,
heartbeatRunId: context?.heartbeatRunId ?? null,
responsibleUserId: context?.responsibleUserId ?? null,
},
})View on GitHub (pinned to 01ad858492)
Solutions
- Inspect the thrown message / `managed.error`: it carries the specific reason (unauthorized member, incomplete identity, no repository access, unresolvable personal credential) and fix that underlying condition.
- Reconnect the managed GitHub connection: reinstall the GitHub App on the organization/repositories and re-authorize the OAuth grant so a fresh access token exists.
- If the identity is a personal (user) connection, ensure the owner is an active company member with a non-viewer role and that their GitHub user secret is still present and resolvable.
- If managed identity is not wanted, disconnect/remove the managed GitHub connection for the company so resolution falls through to company secrets or GITHUB_TOKEN/GH_TOKEN env credentials.
- For self-hosted operators, as a non-managed fallback, set GITHUB_TOKEN or GH_TOKEN in the server process environment or store the token as a company secret with one of the well-known names.
Example fix
// before: managed GitHub App uninstalled, resolution fails closed
const provider = createGitRemoteAuthProvider(db, companyId, { issueId });
const credential = await provider(remoteUrl); // throws 'Managed GitHub connection is unavailable'
// after: operator reinstalls/re-authorizes the GitHub App (or disconnects it so env token applies)
// env: GITHUB_TOKEN=ghp_...
const credential = await provider(remoteUrl); // returns { token, source: "server_env" } Defensive patterns
Strategy: fallback
Validate before calling
const managed = await resolveManagedGitHubCredential(db, secretService(db), companyId, { issueId });
if (managed.configured && !managed.credential) {
console.error("Managed GitHub identity unusable:", managed.error); // fix before any git op
} Type guard
function hasManagedCredential(m: { configured: boolean; credential?: unknown }): m is { configured: true; credential: NonNullable<unknown> } {
return m.configured && m.credential != null;
} Try / catch
try {
const credential = await provider(remoteUrl);
} catch (err) {
if (err instanceof Error && err.message.includes("Managed GitHub connection")) {
// alert operator to reconnect the GitHub App; do not silently fall back
}
throw err;
} Prevention
- Monitor the managed connection's OAuth expiry and refresh health before runs start.
- Alert when a GitHub App installation count or repository count drops to zero.
- Keep identity owners as active non-viewer members; audit membership changes.
- Remember resolution fails closed: never rely on secret/env fallback while a managed connection is configured.
When it happens
Trigger: Calling `createGitRemoteAuthProvider(db, companyId, context)(remoteUrl)` (or `resolveCredential`) when: (1) a managed GitHub connection exists for the company but the OAuth grant is missing/expired and refresh via `refreshOAuthGrantCredentials` fails; (2) the identity owner is not an active non-viewer company member; (3) the grant's credential secret ref for `oauth.access_token` or the GitHub tenant record is missing ('identity is incomplete'); (4) the GitHub app installation or repository access was revoked (installationCount/repositoryCount < 1); (5) the personal credential secret cannot be resolved.
Common situations: A GitHub App installation was uninstalled from the org; the user who owns a personal GitHub connection left the company or was downgraded to viewer; the OAuth token expired and the refresh token was revoked; the connection was partially deleted leaving no access_token secret ref; an operator configured a managed connection expecting secret fallback that intentionally never happens (fails closed by design).
Related errors
- Discord bot is not installed in the selected server
- GitHub inventory failed: this chat connection requires a ded
- GitHub receipt runtime unavailable
- github_identity_unavailable
- OpenCode evals require exact version 1.18.17; received ${ver
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/a1eea9a05a3b1a82.
Report an issue: GitHub.