Dokploy / Dokploy/dokploy

Multiple labels on one PR create duplicate preview deployments (race in labeled webhook handling)

Open
#5,086 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
37.4k
Forks
3k
Avg merge
1d 3h
Merged PRs (30d)
73

Description

To Reproduce
  1. Create an application with preview deployments enabled and a preview label filter configured (default preview).
  2. Open a PR carrying several labels at once, e.g. gh pr create --label bug --label frontend --label preview (or add 3 labels in one action in the GitHub UI).
  3. Watch the PR conversation.
Current vs. Expected behavior

Current: one preview deployment is created per webhook delivery. GitHub sends one pull_request delivery per label (labeled × 3) plus opened, so the PR above gets 4 separate "Dokploy Preview Deployment" comments and 4 preview deployments for the same PR/commit. Observed on a PR where 3 labels were attached in the same second: 4 bot comments, ~8–9s apart.

Expected: one preview deployment per PR, regardless of how many labels arrive or how many deliveries GitHub sends.

Root cause (from reading canary @ d542967a)

apps/dokploy/pages/api/deploy/github.ts includes labeled in shouldCreateDeployment (L364–375) and guards creation only with a non-atomic read-then-write:

const previewDeploymentResult =
    await findPreviewDeploymentByApplicationId(app.applicationId, prId);
...
if (!previewDeploymentResult && shouldCreateDeployment) {
    const previewDeployment = await createPreviewDeployment({ ... });

Three things make the race window seconds wide, so concurrent deliveries all pass the !previewDeploymentResult check:

  1. No unique constraint on (applicationId, pullRequestId) in packages/server/src/db/schema/preview-deployments.ts — the only unique column is appName, which gets a random suffix and never collides. Nothing at the DB layer rejects the duplicate row.
  2. createPreviewDeployment posts the GitHub comment before inserting the row (packages/server/src/services/preview-deployment.ts L163–178) — the check→insert window spans a network round-trip.
  3. Each delivery also does a checkUserRepositoryPermissions GitHub round-trip before the dedup lookup (github.ts L417–424), staggering the deliveries further.

This looks like a reintroduction of #3469: #3642 fixed it by excluding labeled from deployment creation, #3956 showed that broke label-filter workflows, and #3960 re-added labeled — leaving the racy findFirst as the only duplicate guard.

Suggested fix
  • Add a composite unique constraint on previewDeployments (applicationId, pullRequestId) and have createPreviewDeployment insert first (onConflictDoNothing), posting the PR comment only when the insert wins. A losing concurrent delivery then never comments.
  • Note even with the constraint, deliveries that find the existing row still each enqueue a redeploy (github.ts L509–535) — one labeled delivery per label means N queued builds for the same head SHA; a per-(prId, head.sha) short-circuit would collapse those too.
Provide environment information
  • Dokploy version: v0.29.14 (self-hosted, Docker, Ubuntu VPS)
  • Integration: GitHub App webhooks
  • Affected since v0.28.6 (first release containing #3960); code present on current canary (d542967a, 2026-08-14).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with apps/dokploy/pages/api/deploy/github.ts, especially shouldCreateDeployment, the permission check, and the redeploy enqueue path; then read packages/server/src/db/schema/preview-deployments.ts and packages/server/src/services/preview-deployment.ts. Reproduce concurrent labeled deliveries and verify that one PR/commit produces one preview deployment and comment, without duplicate queued builds.

Written by the indexing model from the issue text.

Assessment

Tech stack
github, typescript
Domain
backend, databases, devops
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.