#5469·dokploy

Docker source: "Login Succeeded" then "pull access denied" — Registry URL never reaches the image name

Author: RackmeCreated Sep 16, 2026Updated Sep 16, 2026
Labelsneeds-triage🔍

To Reproduce

  1. Have a working private registry (e.g. registry.example.com, image published at registry.example.com/team/app:latest).
  2. Add it under Registry management and hit test — it succeeds.
  3. Create an application with source type Docker and fill the Docker Provider form:
    • Docker Image: app:latest
    • Registry URL: https://registry.example.com/team/
    • Username / Password: valid registry credentials
  4. Deploy.

Current vs. Expected behavior

Current — the deployment fails with two lines that contradict each other:

Pulling app:latest
Login Succeeded
Error response from daemon: pull access denied for app, repository does not exist or may require 'docker login'
❌ Pulling image failed

The login goes to the right registry; the pull goes to Docker Hub. buildRemoteDocker (packages/server/src/utils/providers/docker.ts) uses the two fields in two different commands:

typescript
const { registryUrl, dockerImage, username, password } = application;
echo `Pulling ${dockerImage}`;
safeDockerLoginCommand(registryUrl || "", username, password)   // registryUrl used here
docker pull ${quote([dockerImage])}                              // and nowhere else

registryUrl is never prepended to the image, so app:latest is resolved by Docker to docker.io/library/app:latest. The error message confirms it — it names app with no host; had the daemon contacted the private registry it would read pull access denied for registry.example.com/team/app.

Expected — one of:

  • the deployment fails with a message that says the image needs the registry host, or
  • the Registry URL is composed into the image (see Additional context — I don't think this one is safe).

Either way, not a "Login Succeeded" immediately followed by an auth failure against a registry that was never contacted.

Provide environment information

bash
Operating System:
RockyLinux (sudo mode)

Which area(s) are affected? (Select all that apply)

Application

Are you deploying the applications where Dokploy is installed or on a remote server?

Remote server

Additional context

Why this is easy to hit. The UI suggests the short form: the Docker Image placeholder is node:16 and the Registry URL field sits right next to it, which reads as "these two get joined". Nothing validates the pair, and the failure mode is a confident wrong answer rather than a visible error.

The product uses both conventions. On the push side Dokploy does compose (packages/server/src/utils/cluster/upload.ts, getRegistryTag):

typescript
return finalRegistry ? `${finalRegistry}/${targetPrefix}/${repositoryName}` : ...

Same two fields, opposite contract, no indication in the UI which one you're in.

This is not a regression. I walked git log -p --follow on providers/docker.ts back to the initial commit: docker pull ${dockerImage} has been verbatim throughout. The only changes to that line are log plumbing (a05b75fc6), the error branch (0d3c978aa) and shell-quoting (cba0b253c, whose own test pins that a legitimate reference round-trips unchanged). The now-deleted local path pullImage did the same thing with spawnAsync. So it has never worked this way — it is a long-standing UX trap, not something that broke.

Second, quieter issue. getAuthConfig (packages/server/src/utils/builders/index.ts) puts registryUrl straight into AuthConfig.serveraddress, which Swarm matches against the registry host of the image on the target node. A pasted https://registry.example.com/team/ carries a scheme and a path where a host is expected, so the node-side pull can 401 even after the build-server pull succeeds. Note the service is created against application.serverId, not the build server — so these are two different machines.

On auto-composition. It looks like the obvious fix but I don't think it is safe: someone with a private Registry URL who sets Docker Image to nginx:latest (a public Hub image) works today and would break. Happy to implement it if maintainers prefer it, but the PR I'm opening reports the mismatch instead of rewriting the image.

Will you send a PR to fix it?

Yes