Stirling-Tools/Stirling-PDF · error · Error

No team to invite to

Error message

No team to invite to

What it means

Thrown by the SaaS usersBackend inviteMember() when neither the explicit teamId parameter nor resolveTeam() yields a team ID. resolveTeam() queries the current user's team context; if the user has no team (new account, personal team not yet created, or team fetch failed), tid is null and inviting is impossible.

Source

Thrown at frontend/editor/src/saas/portal/usersBackend.ts:228

  fetchAuthConfig(): Promise<AdminAuthConfig> {
    // SaaS is Supabase-authed: no direct password create, no self-hosted
    // OAuth/SAML provider list. Static, no network call (the login probe is an
    // admin/self-hosted endpoint).
    return Promise.resolve({
      canDirectCreate: false,
      hasOauth: false,
      hasSaml: false,
    });
  },

  async inviteMember(
    email: string,
    _role: Extract<RoleId, "admin" | "member">,
    teamId?: number,
  ): Promise<InviteResult> {
    // SaaS invitations are always plain members; role is ignored.
    const tid = teamId ?? (await resolveTeam())?.teamId;
    if (tid == null) throw new Error("No team to invite to");
    await apiClient.local.json(`/api/v1/team/invite`, {
      method: "POST",
      body: { teamId: tid, email },
    });
    return { successCount: 1, failureCount: 0 };
  },

  async renameTeam(teamId: number, newName: string): Promise<void> {
    await apiClient.local.json(`/api/v1/team/${teamId}/rename`, {
      method: "POST",
      body: { newName },
    });
  },

  async removeMember(member: Member): Promise<void> {
    if (member.teamId == null) {
      throw new Error("Member has no team to be removed from");
    }

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Ensure the user has a team provisioned before enabling the invite UI (disable the invite button until currentTeam resolves)
  2. Pass an explicit teamId from the caller rather than relying on resolveTeam() fallback
  3. If the user has no team, show a 'create team' prompt instead of allowing invite
  4. Retry resolveTeam() or re-fetch teams before throwing

Example fix

// before
const tid = teamId ?? (await resolveTeam())?.teamId;
if (tid == null) throw new Error("No team to invite to");

// after
const tid = teamId ?? (await resolveTeam())?.teamId;
if (tid == null) {
  throw new Error(
    "No team found. Please create or join a team before inviting members.",
  );
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate team exists before showing invite UI
const team = await resolveTeam();
if (!team?.teamId) {
  setCanInvite(false);
  showCreateTeamPrompt();
  return;
}
setCanInvite(true);

Try / catch

try {
  await inviteMember(email, role);
} catch (e) {
  if (e instanceof Error && e.message.includes('No team')) {
    showCreateTeamPrompt();
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: inviteMember() is called before the user's team context has loaded, or the user genuinely has no team. The teamId parameter is optional and resolveTeam() returns null/undefined.

Common situations: New SaaS user whose personal team hasn't been provisioned yet; team context fetch race condition where the admin portal loads before teams resolve; user in an inconsistent account state after a team deletion.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/3e417fbf3dcb6ea6. Report an issue: GitHub.