Docker source: "Login Succeeded" then "pull access denied" — Registry URL never reaches the image name
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 3k
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 73
Description
To Reproduce
- Have a working private registry (e.g.
registry.example.com, image published at
registry.example.com/team/app:latest). - Add it under Registry management and hit test — it succeeds.
- 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
- Docker Image:
- 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:
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
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):
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/server/src/utils/providers/docker.ts at buildRemoteDocker and trace how registryUrl and dockerImage are passed to login and pull. Compare that flow with getRegistryTag in packages/server/src/utils/cluster/upload.ts and getAuthConfig in packages/server/src/utils/builders/index.ts. Reproduce the private-registry deployment, then make the chosen behavior explicit and verify that both build-server and target-node pulls use consistent registry addressing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, typescript
- Domain
- devops
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100