{"record":{"id":"67c2ee4fe626e841","repo":"nektos/act","slug":"invalid-publish-opts-format-should-be-name-value","errorCode":null,"errorMessage":"invalid publish opts format (should be name=value but got '%s')","messagePattern":"invalid publish opts format \\(should be name=value but got '(.+?)'\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/container/docker_cli.go","lineNumber":915,"sourceCode":"\tif ep.MacAddress != \"\" {\n\t\tma, err := net.ParseMAC(strings.TrimSpace(ep.MacAddress))\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%s is not a valid mac address\", ep.MacAddress)\n\t\t}\n\t\tepConfig.MacAddress = network.HardwareAddr(ma)\n\t}\n\treturn epConfig, nil\n}\n\nfunc convertToStandardNotation(ports []string) ([]string, error) {\n\toptsList := []string{}\n\tfor _, publish := range ports {\n\t\tif strings.Contains(publish, \"=\") {\n\t\t\tparams := map[string]string{\"protocol\": \"tcp\"}\n\t\t\tfor param := range strings.SplitSeq(publish, \",\") {\n\t\t\t\tk, v, ok := strings.Cut(param, \"=\")\n\t\t\t\tif !ok || k == \"\" {\n\t\t\t\t\treturn optsList, fmt.Errorf(\"invalid publish opts format (should be name=value but got '%s')\", param)\n\t\t\t\t}\n\t\t\t\tparams[k] = v\n\t\t\t}\n\t\t\toptsList = append(optsList, fmt.Sprintf(\"%s:%s/%s\", params[\"published\"], params[\"target\"], params[\"protocol\"]))\n\t\t} else {\n\t\t\toptsList = append(optsList, publish)\n\t\t}\n\t}\n\treturn optsList, nil\n}\n\nfunc parseLoggingOpts(loggingDriver string, loggingOpts []string) (map[string]string, error) {\n\tloggingOptsMap := opts.ConvertKVStringsToMap(loggingOpts)\n\tif loggingDriver == \"none\" && len(loggingOpts) > 0 {\n\t\treturn map[string]string{}, fmt.Errorf(\"invalid logging opts for driver %s\", loggingDriver)\n\t}\n\treturn loggingOptsMap, nil\n}","sourceCodeStart":897,"sourceCodeEnd":933,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/container/docker_cli.go#L897-L933","documentation":"convertToStandardNotation converts Docker's long publish syntax (-p published=8080,target=80,protocol=tcp) into the standard host:container/proto form. Each comma-separated parameter must contain '=' with a non-empty key; a fragment like '8080' or '=tcp' (empty key) fails with this error before the container is created.","triggerScenarios":"Passing -p/--publish with '=' present in the value (which routes it to the long-syntax parser) but a malformed list: '-p 8080=,target=80', '-p =8080,target=80', or a stray trailing comma producing an empty-ish param. Note any '=' anywhere in the -p value selects the long format, so 'localhost:8080=80' also trips it.","commonSituations":"Copy-pasting URL-ish or key=value strings into -p; mixing legacy ':=' style; trailing commas in YAML folded option strings; assuming act accepts docker-compose port mappings.","solutions":["Use the standard form -p 8080:80/tcp, or the fully-formed long syntax -p published=8080,target=80,protocol=tcp","Remove stray '=' characters from port values and trailing commas","Check YAML folded scalars for accidental line-join artifacts"],"exampleFix":"# before\noptions: -p localhost:8080=80\n\n# after\noptions: -p 8080:80","handlingStrategy":"validation","validationCode":"for _, p := range ports {\n    if strings.Contains(p, \"=\") {\n        for _, param := range strings.Split(p, \",\") {\n            k, _, ok := strings.Cut(param, \"=\")\n            if !ok || k == \"\" {\n                return fmt.Errorf(\"bad long-syntax publish %q\", p)\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Default to the short -p host:container[/proto] form","Any '=' in a -p value selects the long parser — avoid stray equals","No trailing commas in long-syntax lists"],"tags":["docker","ports","publish","parsing","act"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}