# Troubleshooting Stuck Deployments and Git Sync Errors

When a deploy seems to hang at `Deploying api…` or `Building Developer Portal…`,
or your Git provider stops returning branches with a `Bad Request` or `410 Gone`
error, the cause is usually one of a few known issues. This guide helps you tell
a genuinely stuck deploy from a slow-but-progressing one, fix Git source-control
sync failures, and gather the right details before contacting support.

## How a Zuplo deploy progresses

Every deploy, whether triggered by a Git push, the Zuplo CLI, or a save in the
Portal, runs through two stages in order:

1. **`Deploying api…`**: Zuplo builds your gateway configuration (routes,
   policies, and modules) and rolls it out to the edge.
2. **`Building Developer Portal…`**: Zuplo builds the Developer Portal site from
   your OpenAPI document and portal configuration.

Each stage produces its own build logs. Zuplo separates logs by stage: `api` for
the gateway build and `dev-portal` for the Developer Portal build. Knowing which
stage a deploy stalled in tells you where to look.

:::note

A deploy can finish the `api` stage successfully and still be working on the
`dev-portal` stage. If your gateway is already serving traffic but the deploy
status hasn't flipped to complete, the Developer Portal build is the most likely
place it's still working. See
[The Developer Portal build never finishes](#the-developer-portal-build-never-finishes).

:::

## Is the deploy stuck, or still working?

A deploy that looks frozen in the terminal is often still running on Zuplo's
side. The Zuplo CLI doesn't run the build itself. It starts the deploy and then
_polls_ for the result. The build continues on the server even if the CLI stops
waiting.

### Confirm the server-side status first

Before assuming a deploy failed, check whether it actually completed:

1. Open your [project](https://portal.zuplo.com/+/account/project/) in the Zuplo
   Portal.
2. Check the environment you deployed to. If the build finished, the environment
   shows the new deployment and its URL responds to requests.
3. Send a request to the environment URL (or its
   [health check route](./health-checks.mdx), if you have one) to confirm the
   gateway is live.

If the environment is updated and serving traffic, the deploy succeeded. The CLI
simply stopped waiting before the build reported back.

:::tip

The CLI prints `Deployed to https://...` on success. If you never saw that line
but the Portal shows the environment updated, the deploy completed after the CLI
timed out. Capture the URL from the Portal rather than constructing it from the
branch name. The hostname uses a normalized, truncated form of the environment
name plus a unique identifier.

:::

### Extend the CLI polling timeout

By default the CLI polls every second for up to 250 attempts, a little over four
minutes. Large projects can take longer to build, and when the CLI's poll budget
runs out it stops waiting even though the deploy keeps running on the server.

Increase the timeout with the `POLL_INTERVAL` and `MAX_POLL_RETRIES` environment
variables:

```bash
# Poll every 5 seconds for up to 300 attempts (25 minutes)
POLL_INTERVAL=5000 MAX_POLL_RETRIES=300 zuplo deploy
```

- **`POLL_INTERVAL`**: Milliseconds between polls. Default `1000` (1 second).
- **`MAX_POLL_RETRIES`**: Maximum number of polls before the CLI times out.
  Default `250`.

For the full command reference, see [CLI: deploy](../cli/deploy.mdx).

:::caution

Raising the polling timeout only changes how long the CLI _waits_. It does not
make the build faster, and it does not fix a build that is genuinely failing. If
the deploy never completes server-side no matter how long you wait, treat it as
a failed build and read the logs for the stage that stalled.

:::

## The Developer Portal build never finishes

If the gateway (`api` stage) deploys but the overall deploy hangs at
`Building Developer Portal…`, the problem is in the Developer Portal build, not
your routes or policies.

Common causes:

- **Invalid OpenAPI document**: The portal is generated from your OpenAPI
  document. A malformed `routes.oas.json`, an unresolved `$ref`, or invalid
  schema can stall or fail the portal build. Validate your OpenAPI document and
  fix any errors.
- **A legacy `config/dev-portal.json` file**: Projects migrated from the old
  Developer Portal can carry a stale `config/dev-portal.json` that breaks the
  build. See the [Dev Portal Migration Guide](../dev-portal/migration.mdx) for
  the exact cleanup steps.
- **Custom portal configuration errors**: Errors in your `zudoku.config.tsx` (or
  other portal configuration) can prevent the site from building.

Read the `dev-portal` stage build logs to see the specific error, then redeploy
after fixing it.

## Git source-control sync errors

Zuplo connects to GitHub, GitLab, Bitbucket, and Azure DevOps for source
control. The integration pushes and pulls code between the Portal and your
repository, and it lists branches so you can map them to environments. When that
authorization breaks, branch retrieval fails, often with a `Bad Request` or
`410 Gone` error.

### Why branch retrieval returns `Bad Request` or `410 Gone`

These errors come from the Git provider, not from Zuplo, and they almost always
mean the connection is no longer authorized:

- The OAuth authorization Zuplo uses to reach the provider has **expired or been
  revoked**.
- The repository was **renamed or moved**, which breaks the existing connection.
- The Git app was **uninstalled** or lost access to the repository in the
  provider's settings.

`410 Gone` in particular signals that the resource Zuplo asked for (the branch
list) is no longer available at that location, typically because the
authorization or repository link behind it is stale.

### Reconnect the integration

To restore branch sync, re-authorize the connection:

1. Open your
   [project settings](https://portal.zuplo.com/+/account/project/settings/general)
   in the Zuplo Portal and select **Source Control**.
2. Disconnect the current repository connection.
3. Reconnect and complete the provider's authorization flow again, granting
   access to the repository that holds your Zuplo project.

After reconnecting, retrieving branches should succeed again.

:::caution

Renaming a repository breaks the Zuplo connection. If you renamed or moved the
repository, disconnect and reconnect to restore the link. See
[Rename or Move Project](./rename-or-move-project.mdx) for details.

:::

### Bitbucket-specific notes

Bitbucket integration is available on
[enterprise plans](https://zuplo.com/pricing) and provides push/pull source
control without automatic deployments. You deploy with the Zuplo CLI through
[Bitbucket Pipelines](./custom-ci-cd-bitbucket.mdx).

If reconnecting from the Portal doesn't clear the sync error:

- **Confirm Bitbucket is still enabled for your account.** For
  [bitbucket.org](https://bitbucket.org), Zuplo support enables the integration.
  Contact [support@zuplo.com](mailto:support@zuplo.com) with your Bitbucket
  Workspace ID (found on your Workspace Settings page).
- **For self-hosted Bitbucket, check the OAuth app.** If the OAuth app's client
  secret was rotated or its callback URL or permissions changed, branch
  retrieval fails until the app is reconfigured. The callback URL must be
  `https://portal.zuplo.com` and the app must grant the `repo`, `user`, and
  `read:org` permissions. See
  [Bitbucket Setup](./source-control-setup-bitbucket.mdx).

## Decision tree

Use this to route yourself to the right fix:

| Symptom                                              | Most likely cause                               | First action                                                                                   |
| ---------------------------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| CLI hangs at `Deploying api…` then times out         | Build took longer than the CLI's poll budget    | Check the environment in the Portal; raise `MAX_POLL_RETRIES`                                  |
| CLI reported timeout, but the environment is updated | Deploy completed after the CLI stopped waiting  | None; capture the URL from the Portal                                                          |
| Deploy hangs at `Building Developer Portal…`         | Developer Portal build error                    | Read the `dev-portal` build logs; validate OpenAPI; check for a stale `config/dev-portal.json` |
| Branch list fails with `Bad Request` or `410 Gone`   | Git authorization expired, revoked, or stale    | Reconnect the integration in **Source Control** settings                                       |
| Bitbucket still fails after reconnecting             | Account not enabled, or OAuth app misconfigured | Contact support with your Workspace ID; check the self-hosted OAuth app                        |

## When to contact support

If you've worked through the relevant section above and the deploy or sync still
fails, contact [support@zuplo.com](mailto:support@zuplo.com). Include these
details so support can investigate without a round-trip:

- Your **account** and **project** names.
- The **environment** (branch) you're deploying to.
- The **stage** where it stalls (`api` or `dev-portal`) and the exact message
  you see.
- For sync errors: your **Git provider**, the **repository**, and the exact
  error text (for example, `410 Gone` on branch retrieval).
- The **approximate time** of the failed deploy, in UTC.

## Next steps

- [Source Control & Deployments](./source-control.mdx): how source control and
  deployments fit together across providers.
- [Branch-Based Deployments](./branch-based-deployments.mdx): how branches map
  to environments and how environment URLs are named.
- [Deploying Zuplo from a Monorepo](./monorepo-deployment.mdx): CI/CD
  configuration, schema validation, and health-check timeouts.
- [Troubleshooting (local development)](./local-development-troubleshooting.mdx):
  local dev server, ports, and certificate issues.
