Skip to content

Stack deploy fails if "target" or "published" port is a string #1073

Open

Description

@thaJeztah

As reported by @ushuz #229 (comment)

version: '3.4'
services:
    web:
        image: nginx:alpine
        ports:
          - published: '8080'
            target: 80

Deploying the above produces:

$ docker stack deploy -c docker-compose.yml hello

services.web.ports.0.published must be a integer

The same issue is present for target:

version: '3.4'
services:
    web:
        image: nginx:alpine
        ports:
          - published: 8080
            target: '80'
$ docker stack deploy -c docker-compose.yml hello 

services.web.ports.0.target must be a integer

Changing both to an integer makes this work:

version: '3.4'
services:
    web:
        image: nginx:alpine
        ports:
          - published: 8080
            target: 80
$ docker stack deploy -c docker-compose.yml hello 

Creating network hello_default
Creating service hello_web

Reproduced on:

Client:
 Version:      18.05.0-ce
 API version:  1.37
 Go version:   go1.9.5
 Git commit:   f150324
 Built:        Wed May  9 22:12:05 2018
 OS/Arch:      darwin/amd64
 Experimental: true
 Orchestrator: swarm

Server:
 Engine:
  Version:      18.05.0-ce
  API version:  1.37 (minimum version 1.12)
  Go version:   go1.10.1
  Git commit:   f150324
  Built:        Wed May  9 22:20:16 2018
  OS/Arch:      linux/amd64
  Experimental: true

Activity

  1. thaJeztah commented on May 22, 2018

    @thaJeztah
    MemberAuthor

    Discussing with @vdemeester; this also relates to #839

    The long form --publish published=<port>,target=<port> syntax currently does not support port-ranges (see #839), and expects a single port to be passed (as integer)

    While it's generally good to be strict (we expect a number, so error if it's not a number), from a UX-perspective, I think (my 0.02c) it's ok to accept the port to be passed either as an integer, or as a string containing just a number.

  2. doxxx commented on Jun 7, 2018

    @doxxx

    EDIT: Changing the version to "3.5" made it work.

    Changing both to an integer did not work for me.

    version: "3"
    services:
      db:
        image: couchdb
        ports:
         - published: 5984
           target: 5984
        deploy:
          restart_policy:
            condition: on-failure
      fs:
        image: minio/minio
        command: server /data
        ports:
         - published: 9001
           target: 9000
        deploy:
          restart_policy:
            condition: on-failure
    
    PS> docker stack deploy --compose-file .\docker-compose.yml algdata
    services.db.ports.0 must be a string or number
    

    Docker version 18.05.0-ce, build f150324
    Windows 10

  3. vdemeester commented on Jun 7, 2018

    @vdemeester
    Collaborator

    @doxxx version: "3" means 3.0. The extend form of ports has been introduced in version 3.2, that's why you're getting this error. In version 3.0, ports only support a list of integer (or string)

  4. gordonpn commented on Jun 29, 2022

    @gordonpn

    This is happening with Docker version 20.10.17, build 100c701.

    Fully defined Compose yaml config generated using docker compose convert would give something like:

    (version: "3.9" is added manually)

    version: "3.9"
    name: syncthing
    services:
      syncthing:
        image: syncthing/syncthing
        network_mode: host
        ports:
        - mode: ingress
          target: 8384
          published: "8384"
          protocol: tcp
        - mode: ingress
          target: 22000
          published: "22000"
          protocol: tcp
        - mode: ingress
          target: 22000
          published: "22000"
          protocol: udp
        restart: unless-stopped
    networks:
      traefik-public:
        name: traefik-public
        driver: overlay
        external: true
        attachable: true

    When attempting to deploy to Swarm, two errors will show:

    services.syncthing.ports.0.published must be a integer

    (root) Additional property name is not allowed

    Why is the compose file that is generated using the Docker compose plugin not compatible with Docker stack deploy out of the box?

    Edit: For whoever that stumbles upon this issue again, my current workaround is to pin the version of Docker I am using to deploy to a version < 20.10.15.

    Seems like compose was integrated into Docker Engine version 20.10.15 and onward. I suspect something has changed in the way docker stack deploy reads the config file to deploy to Swarm, but I have yet to look into it myself, to be frank.

  5. nelsonpoon commented on Aug 11, 2022

    @nelsonpoon

    This is happening with Docker version 20.10.17, build 100c701.

    Fully defined Compose yaml config generated using docker compose convert would give something like:

    (version: "3.9" is added manually)

    version: "3.9"
    name: syncthing
    services:
      syncthing:
        image: syncthing/syncthing
        network_mode: host
        ports:
        - mode: ingress
          target: 8384
          published: "8384"
          protocol: tcp
        - mode: ingress
          target: 22000
          published: "22000"
          protocol: tcp
        - mode: ingress
          target: 22000
          published: "22000"
          protocol: udp
        restart: unless-stopped
    networks:
      traefik-public:
        name: traefik-public
        driver: overlay
        external: true
        attachable: true

    When attempting to deploy to Swarm, two errors will show:

    services.syncthing.ports.0.published must be a integer

    (root) Additional property name is not allowed

    Why is the compose file that is generated using the Docker compose plugin not compatible with Docker stack deploy out of the box?

    Edit: For whoever that stumbles upon this issue again, my current workaround is to pin the version of Docker I am using to deploy to a version < 20.10.15.

    Seems like compose was integrated into Docker Engine version 20.10.15 and onward. I suspect something has changed in the way docker stack deploy reads the config file to deploy to Swarm, but I have yet to look into it myself, to be frank.

    I have same problem,

    Verison : Docker version 20.10.17, build 100c701
    Error : services.[ProjectName].ports.0 must be a string or number

    Change on yml

        ports:
          - "80:80"
    

    to

        ports:
          - target: 80
            published: 80
            protocol: tcp
            mode: host
    

    Update:

    I have fix the problem, by change the version to 3.4

    from

    version: "3" 
    

    to

    version: "3.4" 
    
  6. diegobill commented on Feb 10, 2023

    @diegobill

    workaround using sed:

    sed -i '/published:/ s/"//g' docker-compose.yml
    
  7. pschichtel commented on Mar 25, 2025

    @pschichtel

    I'm using docker compose to interpolate env vars in a swarm stack file, unfortunately that insert port numbers with quotes. I'm using this yq expression to correct this in the long form:

    yq eval -i --prettyPrint '.services = (.services | to_entries | map(.value.ports = (.value.ports | map(.published = (.published | to_number)))) | from_entries)' compose-file.yml
  8. flanciskinho commented on Apr 16, 2025

    @flanciskinho

    There is a docker stack config to use on swarm.

    docker stack config  | docker stack deploy --compose-file - [YOUR_STACK_NAME]
    

    This option prevents you from converting invalid values ​​generated by docker compose config. Examples of invalid docker compose config values:

    • outputs published port as a string (must be an integer)
    • outputs cpu as an integer (must be a string)
    • adds the name property (invalid in swarm mode)
  9. phroggar commented on Jun 10, 2025

    @phroggar

    I'm using include and extends from docker compose to organize my swarm setup, example:

    include:
      - path:
          - ../common/backend-network.yml
    
    services:
      # == ClamAV Virus Scan Backend ===================
      clamav:
        extends:
          file: ../common/base-service.yml
          service: base
        image: clamav/clamav:latest
        deploy:
          replicas: 2
    

    Using docker compose -f "$COMPOSE_FILE" config | grep -v '^name:' | docker stack deploy -c - STACKNAME works fine if the compose file does not have published port etc., but requires sed manipulation.

    Using docker stack config would be great, but i'm only getting:

    "Configuration contains forbidden properties", without any helpful output.

    I guess that docker stack config seems to support only a partial set of the compose features, but i feel it would be great to use them ;).

  10. added a commit that references this issue on Oct 31, 2026
    7cf5d8e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions