lima-vm/lima · error

field `provision[%d].content` can only be set when mode is %

Error message

field `provision[%d].content` can only be set when mode is %#q

What it means

`content` is only meaningful for `mode: data` provision entries, where it provides the file body written to `path`. For script modes (system/user/boot/dependency/ansible) or yq mode, setting `content` is invalid; Validate() rejects it so silent misconfiguration cannot happen. The `%#q` in the message renders as `"data"`.

Source

Thrown at pkg/limayaml/validate.go:240

			if !path.IsAbs(*p.Path) {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` must be an absolute path", i))
			}
			if p.Mode == limatype.ProvisionModeData && p.Content == nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].content` must not be empty when mode is %#q", i, p.Mode))
			}
			if p.Mode == limatype.ProvisionModeYQ && p.Expression == nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].expression` must not be empty when mode is %#q", i, p.Mode))
			}
			// FillDefaults makes sure that p.Permissions is not nil
			if _, err := strconv.ParseInt(*p.Permissions, 8, 64); err != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].permissions` must be an octal number: %w", i, err))
			}
		default:
			if (p.Script == nil || *p.Script == "") && p.Mode != limatype.ProvisionModeAnsible {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].script` must not be empty", i))
			}
			if p.Content != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].content` can only be set when mode is %#q", i, limatype.ProvisionModeData))
			}
			if p.Overwrite != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].overwrite` can only be set when mode is %#q", i, limatype.ProvisionModeData))
			}
			if p.Owner != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].owner` can only be set when mode is %#q", i, limatype.ProvisionModeData))
			}
			if p.Path != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].path` can only be set when mode is %#q, or %#q", i, limatype.ProvisionModeData, limatype.ProvisionModeYQ))
			}
			if p.Permissions != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].permissions` can only be set when mode is %#q, or %#q", i, limatype.ProvisionModeData, limatype.ProvisionModeYQ))
			}
			if p.Format != nil {
				errs = errors.Join(errs, fmt.Errorf("field `provision[%d].format` can only be set when mode is %#q", i, limatype.ProvisionModeYQ))
			}
		}
		if p.Playbook != "" {

View on GitHub (pinned to dd909d0973)

Solutions

  1. Add `mode: data` if the entry should write `content` to `path`
  2. Otherwise delete the `content` field and keep/restore `script`
  3. If you want both a file and a script, use two separate provision entries

Example fix

# before
provision:
  - mode: user
    content: |
      hello
# after
provision:
  - mode: data
    path: /etc/motd
    content: |
      hello
Defensive patterns

Strategy: validation

Validate before calling

// Go: content is data-mode only
for i, p := range cfg.Provision {
    mode := limatype.ProvisionModeSystem
    if p.Mode != nil { mode = *p.Mode }
    if p.Content != nil && mode != limatype.ProvisionModeData {
        return fmt.Errorf("provision[%d]: content requires mode data", i)
    }
}

Type guard

func contentAllowed(p limatype.Provision) bool {
    return p.Content == nil || (p.Mode != nil && *p.Mode == limatype.ProvisionModeData)
}

Prevention

When it happens

Trigger: A provision entry with mode system/user/boot/dependency/ansible (or default/empty mode) that also sets `content`, during create/start/restart/edit/apply/template validation.

Common situations: Authoring a file-write entry but forgetting `mode: data`; converting a data entry to a script and leaving content behind; template generators emitting content unconditionally.

Related errors


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