lima-vm/lima · error
field `%s.guest` must be an absolute path, but is %#q
Error message
field `%s.guest` must be an absolute path, but is %#q
What it means
Validate() requires CopyToHost rules to use an absolute guest-side path: if GuestFile is non-empty it must satisfy path.IsAbs() (POSIX semantics, validate.go:393-395). CopyToHost copies files from inside the VM to the host, so the guest path is interpreted in the guest filesystem and must be fully qualified (e.g. /etc/hosts).
Source
Thrown at pkg/limayaml/validate.go:394
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 != "" {
if !filepath.IsAbs(rule.HostFile) {
errs = errors.Join(errs, fmt.Errorf("field `%s.host` must be an absolute path, but is %#q", field, rule.HostFile))
}
}
}
if y.VMType != nil && *y.VMType == limatype.HCS {
if y.HostResolver.Enabled != nil && *y.HostResolver.Enabled && len(y.DNS) > 0 {
errs = errors.Join(errs, errors.New("field `dns` must be empty when field `HostResolver.Enabled` is true"))
}
} else {
if HostResolverEnabled(y) && len(y.DNS) > 0 {
errs = errors.Join(errs, errors.New("field `dns` must be empty when field `HostResolver.Enabled` is true"))
}
}View on GitHub (pinned to dd909d0973)
Solutions
- Prefix the guest path with "/" — use a fully qualified path like /etc/hosts.
- Do not use ~ or environment variables for GuestFile; the guest path must be literal and absolute.
- Run `limactl validate <file>` to catch path issues before starting the instance.
Example fix
# before
copyToHost:
- guest: etc/hosts
host: /tmp/hosts
# after
copyToHost:
- guest: /etc/hosts
host: /tmp/hosts Defensive patterns
Strategy: validation
Validate before calling
for i, r := range cfg.CopyToHost {
if r.GuestFile != "" && !strings.HasPrefix(r.GuestFile, "/") {
return fmt.Errorf("CopyToHost[%d].guest must be absolute: %q", i, r.GuestFile)
}
} Type guard
func absGuestPath(p string) bool { return p != "" && path.IsAbs(p) } Try / catch
if err := limayaml.Validate(y, "strict"); err != nil {
return fmt.Errorf("copyToHost guest path must start with /: %w", err)
} Prevention
- Write guest paths as full POSIX paths (/etc/...), never relative or ~.
- No tilde or env-var expansion happens on guest paths — literalize them.
- Add limactl validate to pre-start checks.
When it happens
Trigger: limayaml.Validate() (via limactl validate/edit/start/restart/clone/rename/template tooling) sees CopyToHost[i].GuestFile set to a relative path like "etc/hosts" or "~/notes".
Common situations: Hand-writing a copyToHost rule with a relative path; assuming ~ expansion applies on the guest side; copying host-style paths into the guest field.
Related errors
- field `%s.host` must be an absolute path, but is %#q
- currently Windows guest is only supported on [%#q, %#q]; got
- field `os` must be one of %#q; got %#q
- field `arch` must be one of %v; got %#q
- field `user.shell` must be one of %v for Windows guest, got
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/4e183717390cfcf3.
Report an issue: GitHub.