{"record":{"id":"7f202d00eba3b3cb","repo":"docker/cli","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":"cli/command/container/opts.go","lineNumber":908,"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":890,"sourceCodeEnd":926,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/container/opts.go#L890-L926","documentation":"Returned in opts.go:908 by convertToStandardNotation when a --publish token using the name=value notation contains a param segment that is empty or has no `=`. The converter expects each comma-separated segment to be key=value (e.g. published=8080,target=80,protocol=tcp).","triggerScenarios":"`docker run -p`/`--publish` with the structured notation where a segment is malformed: `--publish =80`, `--publish published=8080,=tcp`, or a segment with no `=` at all.","commonSituations":"Misunderstanding the structured publish syntax, a stray comma, a typo dropping the key, or a script that builds the token with an empty key.","solutions":["Use the name=value form for every comma-separated segment: published=PORT,target=PORT,protocol=tcp.","Or use the classic short form ip:hostPort:containerPort[/proto].","Ensure no segment is empty and every segment has key and value."],"exampleFix":"# before\ndocker run -p published=8080,,target=80 alpine\n\n# after\ndocker run -p published=8080,target=80 alpine","handlingStrategy":"validation","validationCode":"func validatePublish(tok string) error {\n    if !strings.Contains(tok, \"=\") { return nil } // classic form\n    for _, seg := range strings.Split(tok, \",\") {\n        k, v, ok := strings.Cut(seg, \"=\")\n        if !ok || k == \"\" { return fmt.Errorf(\"bad publish segment %q\", seg) }\n        _ = v\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Deterministic format error; rebuild the token, do not retry.\nif err := validatePublish(tok); err != nil { /* fix or use classic form */ }","preventionTips":["Use name=value for every comma-separated segment.\nPrefer the classic ip:hostPort:containerPort form when unsure.\nAvoid empty segments from trailing/double commas."],"tags":["container","network","ports","flag-validation","create"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}