different-ai/openwork · error · PluginArchRouteFailure
member_not_joined
member_not_joined
Error message
Connector creator member has not joined the organization.
What it means
Thrown when the connector creator's member row exists and is active, but `member.userId` is null — i.e. the membership record has not yet been claimed by a user who actually joined (completed sign-up/invitation acceptance). The route cannot build an actor context without a user id, so it fails with 404 member_not_joined.
Source
Thrown at ee/apps/den-api/src/routes/org/plugin-system/store.ts:5875
throw new PluginArchRouteFailure(404, "organization_not_found", "Organization not found for connector instance.")
}
const memberRows = await db
.select()
.from(MemberTable)
.where(and(
eq(MemberTable.organizationId, input.connectorInstance.organizationId),
eq(MemberTable.id, input.connectorInstance.createdByOrgMembershipId),
isNull(MemberTable.removedAt),
))
.limit(1)
const member = memberRows[0] as MemberRow | undefined
if (!member) {
throw new PluginArchRouteFailure(404, "member_not_found", "Connector creator member not found.")
}
if (!member.userId) {
throw new PluginArchRouteFailure(404, "member_not_joined", "Connector creator member has not joined the organization.")
}
return {
automation: true,
memberTeams: [],
session: null,
organizationContext: {
currentMember: {
createdAt: member.createdAt,
id: member.id,
isOwner: roleIncludesOwner(member.role),
joinedAt: member.joinedAt,
role: member.role,
userId: member.userId,
},
invitations: [],
members: [],
organization: {View on GitHub (pinned to 2b7df46e8a)
Solutions
- Have the invited user accept the organization invitation so the membership gets a userId.
- Re-assign the connector instance's createdByOrgMembershipId to a member whose userId is set.
- If the pending membership is abandoned, remove it and re-create the connector under an active member.
Example fix
// before
const member = await getMember(membershipId)
await resolveConnectorActor(member) // member.userId is null -> member_not_joined
// after
if (!member.userId) {
const joined = await db.select().from(MemberTable).where(and(eq(MemberTable.organizationId, orgId), isNotNull(MemberTable.userId), isNull(MemberTable.removedAt))).limit(1)
await reassignConnectorCreator(connectorInstanceId, joined[0].id)
}
await resolveConnectorActor(joined[0]) Defensive patterns
Strategy: validation
Validate before calling
const member = await getMember(instance.createdByOrgMembershipId)
if (member && !member.userId) throw new Error('Creator has a pending invitation; complete signup or reassign the connector') Type guard
function hasJoined(row: MemberRow): row is MemberRow & { userId: string } { return typeof row.userId === 'string' && row.userId.length > 0 } Try / catch
try {
await resolveConnectorActor({ connectorInstanceId })
} catch (e) {
if (e instanceof PluginArchRouteFailure && e.code === 'member_not_joined') {
await reassignConnectorCreator(connectorInstanceId, await firstJoinedMember(orgId))
} else throw e
} Prevention
- Track invitation acceptance and block connector creation for unjoined members
- Re-assign automations when invitations lapse
- Alert on membership rows without userId older than a threshold
When it happens
Trigger: Resolving a connector instance created by an invited-but-not-yet-accepted membership; a membership row provisioned programmatically (e.g. by SCIM or a script) that never got a userId attached.
Common situations: Admin invites a teammate, the teammate creates the connector in a pending state, invite is never accepted; automated provisioning creates membership rows before users complete onboarding.
Related errors
- member_not_found
- organization_not_found
- invalid_github_materialization_context
- github_connector_account_required
- automation_owner_inactive
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/bc7785fde9b48331.
Report an issue: GitHub.