lima-vm/lima · error
field `%s.proto` must be %#q, %#q, or %#q
Error message
field `%s.proto` must be %#q, %#q, or %#q
What it means
Lima's limayaml.Validate() rejects a port-forwarding rule whose `proto` field is not one of the three allowed constants: ProtoTCP ("tcp"), ProtoUDP ("udp"), or ProtoAny ("any"). The switch at validate.go:376-379 falls through to default for any other value. The error is joined into the aggregate validation error list produced by `limactl validate`, `limactl edit`, `limactl start` (via templateArgs/applyYQ), instance restart, and clone/rename.
Source
Thrown at pkg/limayaml/validate.go:379
if !filepath.IsAbs(rule.HostSocket) {
// should be unreachable because FillDefault() will prepend the instance directory to relative names
errs = errors.Join(errs, fmt.Errorf("field `%s.hostSocket` must be an absolute path, but is %#q", field, rule.HostSocket))
}
if rule.GuestSocket == "" && rule.GuestPortRange[1]-rule.GuestPortRange[0] > 0 {
errs = errors.Join(errs, fmt.Errorf("field `%s.hostSocket` can only be mapped from a single port or socket. not a range", field))
}
} else if rule.GuestPortRange[1]-rule.GuestPortRange[0] != rule.HostPortRange[1]-rule.HostPortRange[0] {
errs = errors.Join(errs, fmt.Errorf("field `%s.hostPortRange` must specify the same number of ports as field `%s.guestPortRange`", field, field))
}
if len(rule.HostSocket) >= osutil.UnixPathMax {
errs = errors.Join(errs, fmt.Errorf("field `%s.hostSocket` must be less than UNIX_PATH_MAX=%d characters, but is %d",
field, osutil.UnixPathMax, len(rule.HostSocket)))
}
switch rule.Proto {
case limatype.ProtoTCP, limatype.ProtoUDP, limatype.ProtoAny:
default:
errs = errors.Join(errs, fmt.Errorf("field `%s.proto` must be %#q, %#q, or %#q", field, limatype.ProtoTCP, limatype.ProtoUDP, limatype.ProtoAny))
}
if rule.Reverse && rule.GuestSocket == "" {
errs = errors.Join(errs, fmt.Errorf("field `%s.reverse` must be %t", field, false))
}
if rule.Reverse && rule.HostSocket == "" {
errs = errors.Join(errs, fmt.Errorf("field `%s.reverse` must be %t", field, false))
}
// Not validating that the various GuestPortRanges and HostPortRanges are not overlapping. Rules will be
// processed sequentially and the first matching rule for a guest port determines forwarding behavior.
}
for i, rule := range y.CopyToHost {
field := fmt.Sprintf("CopyToHost[%d]", i)
if rule.GuestFile != "" {
if !path.IsAbs(rule.GuestFile) {
errs = errors.Join(errs, fmt.Errorf("field `%s.guest` must be an absolute path, but is %#q", field, rule.GuestFile))
}
}
if rule.HostFile != "" {View on GitHub (pinned to dd909d0973)
Solutions
- Set the rule's proto to one of exactly: tcp, udp, or any (lowercase).
- If the rule targets both protocols, use `any` rather than omitting or inventing a value.
- Run `limactl validate <file>` before `start`/`edit` to catch the typo early.
Example fix
# before
portForwards:
- guestPort: 80
hostPort: 8080
proto: "TCP"
# after
portForwards:
- guestPort: 80
hostPort: 8080
proto: "tcp" Defensive patterns
Strategy: validation
Validate before calling
allowed := map[string]bool{"tcp": true, "udp": true, "any": true}
for i, r := range cfg.PortForwards {
if !allowed[r.Proto] {
return fmt.Errorf("PortForwards[%d].proto %q invalid; use tcp, udp, or any", i, r.Proto)
}
} Type guard
func validProto(p string) bool { return p == "tcp" || p == "udp" || p == "any" } Try / catch
err := limayaml.Validate(y, "strict")
if err != nil {
var fieldErr *ValidationError
if errors.As(err, &fieldErr) { /* inspect joined field errors */ }
return fmt.Errorf("lima config invalid: %w", err)
} Prevention
- Always write proto values lowercase: tcp, udp, any.
- Run `limactl validate <file>` in CI before limactl start.
- Reuse limatype constants instead of string literals in generated configs.
When it happens
Trigger: Any code path calling limayaml.Validate() on a LimaYAML whose PortForwards[i].Proto is an unlisted string (e.g. "TCP", "sctp", "", "icmp") — specifically: limactl validate/templateValidateAction, limactl edit (editAction), restartAction, applyYQExpressionToExistingInstance, cloneOrRenameAction, or templateArgs evaluation.
Common situations: Typo or wrong-casing `proto: "TCP"` (values are lowercase), copying a rule from a different tool that accepts other protocols, YAML editing that leaves proto empty in a hand-written rule, or programmatic generation writing an invalid enum.
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
- field `%s.reverse` must be %t
- field `%s.hostPort` must be 0 when field `%s.hostSocket` is
- field `%s.hostPort` must match field `%s.hostPortRange[0]`
- field `%s.guestPortRange[1]` must be greater than or equal t
- field `%s.hostPortRange[1]` must be greater than or equal to
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/e05d9c6cd5ad4cb1.
Report an issue: GitHub.