This error occurs when attempting to join a node to a Docker Swarm cluster with an incorrect, malformed, or expired join token. The join token must match exactly what the swarm manager provides and be used for the correct role (worker or manager).
The "invalid join token" error indicates that the token you provided to the `docker swarm join` command is not recognized by the swarm manager. Join tokens are cryptographic secrets that authorize new nodes to join a Docker Swarm cluster in a specific role (worker or manager). Docker Swarm uses these tokens for security - they ensure that only authorized nodes can join your cluster. Each swarm has two separate tokens: one for worker nodes and one for manager nodes. The tokens are generated when you initialize the swarm with `docker swarm init` and can be rotated at any time. Common scenarios where this error appears: - **Copy-paste errors**: The token was not copied completely or includes extra whitespace/characters - **Token type mismatch**: Using a worker token when trying to join as a manager, or vice versa - **Rotated tokens**: The token was rotated on the manager after you copied it, invalidating the old token - **Swarm recreation**: The swarm was re-initialized, generating new tokens - **Automation issues**: Scripts or configuration management tools passing malformed or stale token values
First, get a fresh join token from an existing swarm manager. SSH into any manager node and run:
For worker nodes:
docker swarm join-token workerFor manager nodes:
docker swarm join-token managerThis outputs the complete join command including the token. The output looks like:
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-5k3... 192.168.1.100:2377Copy the entire command exactly as shown, including the IP address and port.
Ensure you're using the right token for your intended role:
- Worker token: Allows the node to join as a worker (runs containers but doesn't participate in swarm management)
- Manager token: Allows the node to join as a manager (participates in Raft consensus and can manage the swarm)
If you accidentally used the wrong token type, get the correct one:
# On a manager node - get worker token only (no command, just token)
docker swarm join-token -q worker
# On a manager node - get manager token only (no command, just token)
docker swarm join-token -q managerThe -q flag outputs just the token string without the full join command, which is useful for automation.
Join tokens are long strings that are easy to truncate or corrupt when copying:
Valid token format:
SWMTKN-1-<25 characters>-<25 characters>Check your token:
1. Ensure it starts with SWMTKN-1-
2. Count the sections - there should be exactly 3 parts separated by hyphens after "SWMTKN-1-"
3. Check for trailing spaces or newline characters
4. Ensure no characters were cut off
Test by echoing the token:
# Store in variable and verify
TOKEN="SWMTKN-1-your-token-here"
echo "Token: [$TOKEN]"
echo "Length: ${#TOKEN}"A valid token is typically 96+ characters long.
If you suspect the token has been compromised or is in an unknown state, rotate it on the manager:
# Rotate worker token
docker swarm join-token --rotate worker
# Rotate manager token
docker swarm join-token --rotate managerThis invalidates all previous tokens for that role and generates a new one. The command also outputs the new join command.
Important: After rotating, update all scripts and documentation that reference the old token - it will no longer work.
If the node was previously part of this or another swarm, it may retain stale state. Leave the current swarm first:
# On the node trying to join
docker swarm leave
# Force leave if necessary (e.g., if it was a manager)
docker swarm leave --forceThen attempt to join again with a fresh token from the manager:
docker swarm join --token SWMTKN-1-... <manager-ip>:2377Note: If you see "This node is already part of a swarm", you must leave first.
When using Ansible, Terraform, or shell scripts, token handling issues are common:
Ansible example (correct approach):
- name: Get worker join token
command: docker swarm join-token -q worker
register: worker_token
delegate_to: "{{ swarm_manager }}"
- name: Join swarm as worker
command: >
docker swarm join
--token {{ worker_token.stdout }}
{{ swarm_manager }}:2377Shell script (correct approach):
# Get token with -q flag for clean output
TOKEN=$(ssh manager-node "docker swarm join-token -q worker")
# Verify token is not empty
if [ -z "$TOKEN" ]; then
echo "Failed to get join token"
exit 1
fi
# Join using the token
docker swarm join --token "$TOKEN" manager-node:2377Common mistakes:
- Using msg or other wrapper keys from Ansible output instead of stdout
- Not quoting the token variable ($TOKEN vs "$TOKEN")
- Including newlines in the token string
The token validation happens on the manager node. Ensure network connectivity:
# Test connectivity to manager on swarm port
nc -zv <manager-ip> 2377
# or
telnet <manager-ip> 2377
# Check if firewall allows port 2377
sudo ufw status | grep 2377
sudo firewall-cmd --list-ports | grep 2377Required ports for Docker Swarm:
- TCP 2377: Cluster management communications
- TCP/UDP 7946: Communication among nodes
- UDP 4789: Overlay network traffic
If the manager is unreachable, the token cannot be validated and the join will fail.
Docker Swarm uses TLS certificates that expire. If certificates are expired or invalid, token validation may fail:
# On a manager node, check certificate status
docker info | grep -A 5 "Swarm"If certificates have expired, you may need to force a new cluster:
# On the primary manager (CAUTION: only if cluster is broken)
docker swarm init --force-new-clusterThis recreates the cluster from the current manager's state, generating new certificates and tokens. All other nodes will need to rejoin.
Note: Only use --force-new-cluster as a last resort when the swarm is in a broken state.
Understanding Docker Swarm join tokens:
Join tokens consist of several parts:
- SWMTKN: Token prefix identifying it as a swarm token
- 1: Token version
- A cryptographic hash derived from the cluster's root CA
- A random secret specific to the role (worker or manager)
Token security best practices:
Docker recommends rotating your swarm join tokens:
- At least every 6 months
- Immediately if a token is exposed (e.g., committed to version control)
- After removing a compromised node from the cluster
- When offboarding team members with cluster access
Storing tokens securely:
Never hardcode tokens in scripts or configuration files committed to version control. Instead:
- Use secret management tools (HashiCorp Vault, AWS Secrets Manager)
- Retrieve tokens dynamically during deployment
- Use environment variables with restricted access
Token rotation in production:
When rotating tokens in production:
1. Rotate the token on the manager
2. Update any automation that stores the token
3. Verify new nodes can join with the new token
4. Document the rotation in your change management system
Debugging Ansible docker_swarm module:
If using Ansible's docker_swarm module and getting "invalid join token":
# Debug: Print the actual token being used
- debug:
var: worker_token.stdout
# Ensure you're using stdout, not the full result object
- name: Join swarm
docker_swarm:
state: join
join_token: "{{ worker_token.stdout }}" # NOT worker_token
remote_addrs:
- "{{ manager_ip }}:2377"Proxy server interference:
If your environment uses a proxy server, Docker swarm join commands might route through the proxy incorrectly. Add the manager IP to NO_PROXY:
export NO_PROXY=$NO_PROXY,<manager-ip>
docker swarm join --token ... <manager-ip>:2377dockerfile parse error line 5: unknown instruction: RRUN
How to fix 'unknown instruction' Dockerfile parse error in Docker
Error response from daemon: manifest for nginx:nonexistent not found: manifest unknown: manifest unknown
How to fix 'manifest for image:tag not found' in Docker
Error response from daemon: invalid reference format: repository name must be lowercase
How to fix 'repository name must be lowercase' in Docker
Error response from daemon: No such image
How to fix 'No such image' in Docker
Error response from daemon: Container is not running
How to fix 'Container is not running' when using docker exec