Skip to content

Preview deployments with previewLabels fail due to webhook race condition #3956

@simpautus

Description

@simpautus

Bug Description

Preview deployments configured with previewLabels fail ~80% of the time because the labeled webhook action cannot create new preview deployment records — only opened, synchronize, and reopened can.

Root Cause

In apps/dokploy/pages/api/deploy/github.ts, the shouldCreateDeployment flag excludes labeled:

const shouldCreateDeployment =
    action === "opened" ||
    action === "synchronize" ||
    action === "reopened";

This interacts with GitHub's non-deterministic webhook ordering (documented in GitHub Community Discussion #69337). When a PR is created with a label (e.g. gh pr create --label preview), GitHub fires both opened and labeled webhooks, but their delivery order is unpredictable.

Failure case (~80% of the time):

  1. opened arrives first — PR has no label yet in the payload → label check (if (!hasLabel) continue) skips the app → no preview created
  2. labeled arrives second — label check passes, but shouldCreateDeployment is false → cannot create a new preview deployment record → nothing happens

Success case (~20% of the time):

  1. labeled arrives first — shouldCreateDeployment is false, no effect
  2. opened arrives second — by now the label is present in the payload → label check passes → preview created

The handler returns {"message": "Apps Deployed"} with HTTP 200 in both cases, making this silent.

Steps to Reproduce

  1. Configure an application with preview deployments enabled and previewLabels set (e.g., ["preview"])
  2. Create a PR targeting the configured branch with the label applied at creation time (e.g., gh pr create --label preview)
  3. Observe that preview deployment is created inconsistently — fails most of the time

Evidence

We tested by creating 5 identical PRs with gh pr create --label test and observed the webhook delivery order:

PR Webhook order Would preview work?
1 opened → labeled No
2 opened → labeled No
3 labeled → opened Yes
4 opened → labeled No
5 opened → labeled No

4 out of 5 failed (80% failure rate).

Suggested Fix

Add "labeled" to the shouldCreateDeployment condition:

const shouldCreateDeployment =
    action === "opened" ||
    action === "synchronize" ||
    action === "reopened" ||
    action === "labeled";

unlabeled should remain excluded — removing a label should not create new preview deployments.

This also fixes the secondary use case where a user opens a PR first and adds the label later — currently that also fails silently.

Affected Versions

All versions from v0.25.0 (when previewLabels was introduced in PR #2231) through v0.28.5 (latest).

Environment

  • Dokploy v0.28.4, self-hosted
  • GitHub App integration (not OAuth)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions