lima-vm/lima · error

field `%s.guestPort` must be 0 when field `%s.guestSocket` i

Error message

field `%s.guestPort` must be 0 when field `%s.guestSocket` is set

What it means

Port forward rules carry both a scalar `guestPort` and a `guestPortRange` [start,end]. When a specific guestPort is set, Validate() requires it to equal guestPortRange[0] so the two representations stay consistent. This is a redundancy check after limayaml defaulting/normalization, so it usually indicates hand-edited or programmatically inconsistent rules.

Source

Thrown at pkg/limayaml/validate.go:314

			}
		}
		if p.Script != nil && !strings.HasPrefix(*p.Script, "#!") {
			errs = errors.Join(errs, fmt.Errorf("field `probe[%d].script` must start with a '#!' line", i))
		}
		switch p.Mode {
		case limatype.ProbeModeReadiness:
		default:
			errs = errors.Join(errs, fmt.Errorf("field `probe[%d].mode` can only be %#q", i, limatype.ProbeModeReadiness))
		}
	}
	for i, rule := range y.PortForwards {
		field := fmt.Sprintf("portForwards[%d]", i)
		if *rule.GuestIPMustBeZero && !rule.GuestIP.Equal(net.IPv4zero) {
			errs = errors.Join(errs, fmt.Errorf("field `%s.guestIPMustBeZero` can only be true when field `%s.guestIP` is 0.0.0.0", field, field))
		}
		if rule.GuestPort != 0 {
			if rule.GuestSocket != "" {
				errs = errors.Join(errs, fmt.Errorf("field `%s.guestPort` must be 0 when field `%s.guestSocket` is set", field, field))
			}
			if rule.GuestPort != rule.GuestPortRange[0] {
				errs = errors.Join(errs, fmt.Errorf("field `%s.guestPort` must match field `%s.guestPortRange[0]`", field, field))
			}
			// redundant validation to make sure the error contains the correct field name
			if err := validatePort(field+".guestPort", rule.GuestPort); err != nil {
				errs = errors.Join(errs, err)
			}
		}
		if rule.HostPort != 0 {
			if rule.HostSocket != "" {
				errs = errors.Join(errs, fmt.Errorf("field `%s.hostPort` must be 0 when field `%s.hostSocket` is set", field, field))
			}
			if rule.HostPort != rule.HostPortRange[0] {
				errs = errors.Join(errs, fmt.Errorf("field `%s.hostPort` must match field `%s.hostPortRange[0]`", field, field))
			}
			// redundant validation to make sure the error contains the correct field name
			if err := validatePort(field+".hostPort", rule.HostPort); err != nil {

View on GitHub (pinned to dd909d0973)

Solutions

  1. Remove `guestPortRange` from the YAML and keep only `guestPort`
  2. Or set `guestPortRange[0]` equal to the guestPort value
  3. For a port range forward, omit the scalar guestPort and only use guestPortRange

Example fix

// before
portForwards:
- guestPort: 8080
  guestPortRange: [8081, 8090]
  hostPort: 8080
// after
portForwards:
- guestPort: 8080
  hostPort: 8080
Defensive patterns

Strategy: validation

Validate before calling

for i, r := range cfg.PortForwards {
    if r.GuestPort != 0 && r.GuestPort != r.GuestPortRange[0] {
        return fmt.Errorf("portForwards[%d].guestPort must match guestPortRange[0]", i)
    }
}

Type guard

func guestPortConsistent(r limatype.PortForward) bool {
    return r.GuestPort == 0 || r.GuestPort == r.GuestPortRange[0]
}

Prevention

When it happens

Trigger: Calling limactl validate/start/etc. with a portForwards rule where `guestPort: N` but `guestPortRange: [M, ...]` with M != N (typically after hand-editing or building the struct directly without defaulting).

Common situations: Manually writing guestPortRange alongside guestPort in lima.yaml; constructing PortForward structs in Go and filling one but not the other; version changes where the range field became part of the surface.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/b737794dced72483. Report an issue: GitHub.