fix: route organization creation through auth hooks#5055
Conversation
|
Ready to review this PR? Stage has broken it down into 1 individual chapter for you:
Chapters generated by Stage for commit 4feea34 on Jun 2, 2026 9:20pm UTC. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThe tRPC organization router's create mutation now imports ChangesOrganization Creation Delegation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews. |
Greptile SummaryThis PR fixes second-organization billing setup by routing the tRPC
Confidence Score: 3/5The core fix is correct and necessary, but the create mutation can silently return null to callers if auth.api.createOrganization does not produce an organization, leaving the client with no error signal. The existing codebase at packages/auth/src/server.ts already defends against a null return from auth.api.createOrganization with personalOrg?.id ?? null, yet the new tRPC handler returns the result directly without any null check. If the call fails silently, downstream code receives null instead of an organization object and no TRPCError is raised. packages/trpc/src/router/organization/organization.ts — specifically the new create mutation return value handling.
|
| Filename | Overview |
|---|---|
| packages/trpc/src/router/organization/organization.ts | Replaces manual DB inserts with auth.api.createOrganization to route through Better Auth hooks; return value is not null-checked, which can silently return null to the caller on failure. |
Sequence Diagram
sequenceDiagram
participant Client
participant tRPC as tRPC create handler
participant BetterAuth as auth.api.createOrganization
participant DB as Database
participant Hooks as afterCreateOrganization hook
participant Stripe
Client->>tRPC: organization.create(name, slug, logo)
tRPC->>tRPC: domain guard check
tRPC->>BetterAuth: "createOrganization({ name, slug, logo, userId })"
BetterAuth->>DB: INSERT organizations
BetterAuth->>DB: INSERT members (owner)
BetterAuth->>Hooks: afterCreateOrganization
Hooks->>Stripe: customers.create(...)
Hooks->>DB: seedDefaultStatuses(org.id)
BetterAuth-->>tRPC: organization (or null)
tRPC-->>Client: organization
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
packages/trpc/src/router/organization/organization.ts:217-226
**Unhandled null return from `createOrganization`**
`auth.api.createOrganization` can return `null` — the in-repo call at `packages/auth/src/server.ts:189` already handles this with `personalOrg?.id ?? null`. Here the return value is used directly as the mutation result: if Better Auth returns `null` (e.g., a slug collision after the domain guard or an internal error in the hook chain), the tRPC mutation silently returns `null` to the caller instead of throwing a `TRPCError`. A null result will silently fail any downstream code that expects an organization object, and the user gets no meaningful error message.
Reviews (1): Last reviewed commit: "fix billing upgrade for second orgs" | Re-trigger Greptile
There was a problem hiding this comment.
No issues found across 1 file
Architecture diagram
sequenceDiagram
participant Client as Desktop Client
participant TRPC as tRPC Router
participant BA as Better Auth
participant DB as Database
participant Stripe as Stripe API
participant Internal as Internal Hooks
Note over Client,Internal: Organization Creation Flow
Client->>TRPC: CHANGED: tRPC organization.create
TRPC->>BA: CHANGED: auth.api.createOrganization({body:{name,slug,logo,userId}})
Note over BA: AFTER: New organization created
BA->>DB: Create organization record
BA->>DB: Create owner membership record
BA-->>BA: Trigger afterCreateOrganization hook
BA->>Internal: Run default status seeding hook
Internal->>DB: Insert default statuses
Internal-->>BA: Statuses created
BA->>Stripe: Run Stripe customer creation hook
Stripe-->>BA: Customer created
BA-->>TRPC: Return created organization
TRPC-->>Client: Return organization response
Note over Client,Internal: Key Change: Better Auth now handles all side effects<br/>instead of direct DB inserts and manual hook calls
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
Bundled fixes since 0.2.21 (no command-surface changes): - #5067 pty-daemon: raise RLIMIT_NOFILE + surface real spawn errno - #5066 projects: restrict deletion to organization owners - #5055 route organization creation through auth hooks Also syncs bun.lock with the desktop 1.12.2 / host-service 0.8.18 bump that landed in e173c89 without a lockfile update.
* chore(desktop): bump version to 1.12.2 (host-service 0.8.17 -> 0.8.18) * release(cli): cut cli v0.2.22 Bundled fixes since 0.2.21 (no command-surface changes): - #5067 pty-daemon: raise RLIMIT_NOFILE + surface real spawn errno - #5066 projects: restrict deletion to organization owners - #5055 route organization creation through auth hooks Also syncs bun.lock with the desktop 1.12.2 / host-service 0.8.18 bump that landed in e173c89 without a lockfile update.
Summary
Root Cause
The desktop app creates additional organizations through the tRPC
organization.createroute. That route inserted directly into the database, bypassing Better AuthafterCreateOrganizationhooks where billing setup runs. As a result, second organizations could miss billing lifecycle setup and the upgrade flow would fail to open checkout.Validation
bun run lintbun run typecheckSummary by cubic
Route organization creation through Better Auth to trigger org hooks for billing and default setup, and add error handling for failed creates. Fixes failed upgrade checkout for second organizations created via the desktop app.
auth.api.createOrganizationto run Stripe and default setup hooks.TRPCErrorwhencreateOrganizationreturns no org to prevent silent failures.Written for commit 4feea34. Summary will update on new commits.
Summary by CodeRabbit