Skip to content

Commit 661249c

Browse files
committed
fix: tolerate duplicate dev environment creation during concurrent invite acceptance
When two invite-accept requests race for the same member, both can observe a project as missing its development environment and attempt to create it. The loser hit the unique constraint on (projectId, slug, orgMemberId) and the resulting P2002 error propagated, failing the accept with an incomplete-setup error even though the environment had already been created. Catch P2002 in the per-project creation loop and treat the project as already provisioned, matching the existing P2002 handling for the org-membership row. Non-P2002 errors still surface the incomplete-setup failure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qe3bkKy2Pzgt3E2EE5CMNY
1 parent c936c79 commit 661249c

1 file changed

Lines changed: 28 additions & 10 deletions

File tree

apps/webapp/app/models/member.server.ts

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -215,16 +215,34 @@ export async function provisionMemberDevelopmentEnvironments({
215215
failedProjectId = project.id;
216216
failedProjectIndex = index;
217217

218-
await createEnvironment({
219-
organization,
220-
project,
221-
type: "DEVELOPMENT",
222-
// We set this true but no backfill (yet!?) so never used
223-
// for dev environments
224-
isBranchableEnvironment: true,
225-
member,
226-
maximumConcurrencyLimit,
227-
});
218+
try {
219+
await createEnvironment({
220+
organization,
221+
project,
222+
type: "DEVELOPMENT",
223+
// We set this true but no backfill (yet!?) so never used
224+
// for dev environments
225+
isBranchableEnvironment: true,
226+
member,
227+
maximumConcurrencyLimit,
228+
});
229+
} catch (error) {
230+
// A concurrent accept (double-clicked Accept, a retry, or the recovery
231+
// path overlapping the normal path) can create this member's
232+
// development environment first. The unique constraint on
233+
// (projectId, slug, orgMemberId) then makes our create fail with P2002.
234+
// The environment already exists, so treat the project as provisioned.
235+
if (
236+
error instanceof PrismaNamespace.PrismaClientKnownRequestError &&
237+
error.code === "P2002"
238+
) {
239+
createdProjectIds.push(project.id);
240+
failedProjectId = undefined;
241+
failedProjectIndex = undefined;
242+
continue;
243+
}
244+
throw error;
245+
}
228246

229247
createdProjectIds.push(project.id);
230248
failedProjectId = undefined;

0 commit comments

Comments
 (0)