different-ai/openwork · error · PluginArchRouteFailure
github_install_user_mismatch
github_install_user_mismatch
Error message
GitHub install state does not match the current user.
What it means
Thrown (409) in completeGithubConnectorInstall when the parsed install state's userId differs from `currentMember.userId` in the actor context. GitHub install callbacks are bound to the initiating user; completing as a different user in the same org is rejected to prevent cross-user install hijacking.
Source
Thrown at ee/apps/den-api/src/routes/org/plugin-system/store.ts:6899
orgId: input.context.organizationContext.organization.id,
returnPath,
secret: env.betterAuthSecret,
userId: input.context.organizationContext.currentMember.userId,
})
return {
redirectUrl: buildGithubAppInstallUrl({ app, state }),
state,
}
}
export async function completeGithubConnectorInstall(input: { context: PluginArchActorContext; installationId: number; state: string }) {
const parsedState = consumeGithubInstallState(input.state)
if (parsedState.orgId !== input.context.organizationContext.organization.id) {
throw new PluginArchRouteFailure(409, "github_install_org_mismatch", "GitHub install state does not match the current organization.")
}
if (parsedState.userId !== input.context.organizationContext.currentMember.userId) {
throw new PluginArchRouteFailure(409, "github_install_user_mismatch", "GitHub install state does not match the current user.")
}
const connectorAccount = await upsertGithubConnectorAccountFromInstallation({
context: input.context,
installationId: input.installationId,
})
return {
connectorAccount,
// Keep install completion fast. The connected-account screen loads repositories next.
repositories: [],
}
}
export async function getGithubConnectorDiscovery(input: { connectorInstanceId: ConnectorInstanceId; context: PluginArchActorContext }) {
const discovery = await resolveGithubConnectorDiscovery(input)
return {
autoImportNewPlugins: discovery.autoImportNewPlugins,View on GitHub (pinned to 2b7df46e8a)
Solutions
- Have the original initiating user complete the callback, or start a new install while logged in as the current user.
- Do not share or forward install completion URLs between users; each user should run their own install flow.
- If automating, keep the same authenticated session for both startGithubConnectorInstall and completeGithubConnectorInstall.
Example fix
// before
// state minted for user A; current session is user B
await completeGithubConnectorInstall({ installationId, state }) // 409 github_install_user_mismatch
// after
await signInAs(stateInitiatingUserId)
await completeGithubConnectorInstall({ installationId, state }) Defensive patterns
Strategy: try-catch
Try / catch
try {
await completeGithubConnectorInstall({ installationId, state })
} catch (e) {
if (e instanceof PluginArchRouteFailure && e.code === 'github_install_user_mismatch') {
await notifyOriginalUserToCompleteInstall() // or start a fresh install as current user
} else throw e
} Prevention
- Keep the same authenticated session for the whole install round trip
- Never forward GitHub callback URLs to other users
- Detect session user changes before the callback and restart the flow
When it happens
Trigger: User A starts the install, user B (same org admin) completes the callback; the session changed users between start and callback (re-login as someone else); replaying another user's install completion URL.
Common situations: Shared admin accounts or password managers swapping sessions mid-flow; forwarding the GitHub redirect URL to a teammate to 'finish the install'; concurrent installs by two admins with mixed-up state params.
Related errors
- github_install_org_mismatch
- Failed to sign in to OpenWork Cloud.
- desktop_signup_deprecated
- t("providers.removal_unsupported")
- Sign in to OpenWork Cloud and choose an organization first.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/b7570fe51db3baac.
Report an issue: GitHub.