{"record":{"id":"120363f7759af1b9","repo":"lima-vm/lima","slug":"field-s-hostportrange-must-specify-the-same-num","errorCode":null,"errorMessage":"field `%s.hostPortRange` must specify the same number of ports as field `%s.guestPortRange`","messagePattern":"field `(.+?)\\.hostPortRange` must specify the same number of ports as field `(.+?)\\.guestPortRange`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/limayaml/validate.go","lineNumber":369,"sourceCode":"\t\t}\n\t\tif rule.GuestSocket != \"\" {\n\t\t\tif !path.IsAbs(rule.GuestSocket) {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.guestSocket` must be an absolute path, but is %#q\", field, rule.GuestSocket))\n\t\t\t}\n\t\t\tif rule.HostSocket == \"\" && rule.HostPortRange[1]-rule.HostPortRange[0] > 0 {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.guestSocket` can only be mapped to a single port or socket. not a range\", field))\n\t\t\t}\n\t\t}\n\t\tif rule.HostSocket != \"\" {\n\t\t\tif !filepath.IsAbs(rule.HostSocket) {\n\t\t\t\t// should be unreachable because FillDefault() will prepend the instance directory to relative names\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.hostSocket` must be an absolute path, but is %#q\", field, rule.HostSocket))\n\t\t\t}\n\t\t\tif rule.GuestSocket == \"\" && rule.GuestPortRange[1]-rule.GuestPortRange[0] > 0 {\n\t\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.hostSocket` can only be mapped from a single port or socket. not a range\", field))\n\t\t\t}\n\t\t} else if rule.GuestPortRange[1]-rule.GuestPortRange[0] != rule.HostPortRange[1]-rule.HostPortRange[0] {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.hostPortRange` must specify the same number of ports as field `%s.guestPortRange`\", field, field))\n\t\t}\n\n\t\tif len(rule.HostSocket) >= osutil.UnixPathMax {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.hostSocket` must be less than UNIX_PATH_MAX=%d characters, but is %d\",\n\t\t\t\tfield, osutil.UnixPathMax, len(rule.HostSocket)))\n\t\t}\n\t\tswitch rule.Proto {\n\t\tcase limatype.ProtoTCP, limatype.ProtoUDP, limatype.ProtoAny:\n\t\tdefault:\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.proto` must be %#q, %#q, or %#q\", field, limatype.ProtoTCP, limatype.ProtoUDP, limatype.ProtoAny))\n\t\t}\n\t\tif rule.Reverse && rule.GuestSocket == \"\" {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.reverse` must be %t\", field, false))\n\t\t}\n\t\tif rule.Reverse && rule.HostSocket == \"\" {\n\t\t\terrs = errors.Join(errs, fmt.Errorf(\"field `%s.reverse` must be %t\", field, false))\n\t\t}\n\t\t// Not validating that the various GuestPortRanges and HostPortRanges are not overlapping. Rules will be","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/limayaml/validate.go#L351-L387","documentation":"When neither side uses sockets, the guest and host port ranges must have the same width: Lima forwards ports one-to-one, so a range of N guest ports needs exactly N host ports. This is checked only in the else branch, i.e. when HostSocket is empty.","triggerScenarios":"Validate on a LimaYAML where portForwards[i] has no hostSocket but GuestPortRange[1]-GuestPortRange[0] != HostPortRange[1]-HostPortRange[0], e.g. guestPortRange: [8080,8082] with hostPortRange: [9080,9081].","commonSituations":"Editing one range but not the other; adding a port to the guest range expecting Lima to pick free host ports automatically (Lima does not for explicit ranges); merge conflicts resolved on one side only.","solutions":["Make both ranges the same length","Or remove hostPortRange so Lima auto-assigns host ports for the guest range","Or split into multiple single-port rules"],"exampleFix":"// before\nportForwards:\n  - guestPortRange: [8080, 8082]\n    hostPortRange: [9080, 9081]\n// after\nportForwards:\n  - guestPortRange: [8080, 8082]\n    hostPortRange: [9080, 9082]","handlingStrategy":"validation","validationCode":"for i, rule := range y.PortForwards {\n  if rule.HostSocket == \"\" && rule.GuestPortRange[1]-rule.GuestPortRange[0] != rule.HostPortRange[1]-rule.HostPortRange[0] {\n    return fmt.Errorf(\"portForwards[%d]: guest and host ranges must have equal width\", i)\n  }\n}","typeGuard":"func rangeWidthsMatch(rule limatype.PortForward) bool { return rule.GuestPortRange[1]-rule.GuestPortRange[0] == rule.HostPortRange[1]-rule.HostPortRange[0] }","tryCatchPattern":"if err := limayaml.Validate(y, false); err != nil {\n  if strings.Contains(err.Error(), \"must specify the same number of ports\") {\n    // resize hostPortRange (or drop it for auto-assignment)\n  }\n}","preventionTips":["Edit guest and host ranges together","Omit hostPortRange to let Lima auto-assign host ports for guest ranges","Add a config lint step that checks range widths"],"tags":["lima","port-forwarding","config-validation"],"backgroundTag":"port-forward-range-mismatch","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}