sipeed/picoclaw · error

invalid expose_paths mode: %s

Error message

invalid expose_paths mode: %s

What it means

ValidateExposePaths accepts only the exact strings "ro" and "rw" as the mode of an expose_paths entry; anything else — including "read-only", "w", "RW", "rw," or the empty string — is rejected with this error echoing the offending value.

Source

Thrown at pkg/isolation/runtime.go:170

	}

	env := make([]string, 0, len(envMap))
	for k, v := range envMap {
		env = append(env, fmt.Sprintf("%s=%s", k, v))
	}
	cmd.Env = env
}

// ValidateExposePaths verifies the user-supplied path exposure rules before a
// child process is started.
func ValidateExposePaths(items []config.ExposePath) error {
	seen := map[string]struct{}{}
	for _, item := range items {
		if item.Source == "" {
			return fmt.Errorf("source is required")
		}
		if item.Mode != "ro" && item.Mode != "rw" {
			return fmt.Errorf("invalid expose_paths mode: %s", item.Mode)
		}

		source := filepath.Clean(item.Source)
		target := item.Target
		if target == "" {
			target = source
		}
		target = filepath.Clean(target)

		if !filepath.IsAbs(source) || !filepath.IsAbs(target) {
			return fmt.Errorf("source and target must be absolute paths")
		}
		if _, ok := seen[target]; ok {
			return fmt.Errorf("duplicate expose_path target: %s", target)
		}
		seen[target] = struct{}{}
	}
	return nil

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Use exactly ro or rw, lowercase, no whitespace
  2. If you copied options from another tool's volume syntax, strip its extras (z, Z, shared, etc.)
  3. Delete the mode key only if your config loader defaults it — as validated here, an absent mode that arrives as "" fails, so prefer setting it explicitly

Example fix

# before
isolation:
  expose_paths:
    - source: /home/me/project
      mode: read-only

# after
isolation:
  expose_paths:
    - source: /home/me/project
      mode: ro
Defensive patterns

Strategy: type-guard

Validate before calling

for _, p := range cfg.Isolation.ExposePaths {
    if !isValidExposeMode(p.Mode) {
        return fmt.Errorf("expose_paths mode must be exactly \"ro\" or \"rw\", got %q", p.Mode)
    }
}

Type guard

func isValidExposeMode(mode string) bool {
    return mode == "ro" || mode == "rw"
}

Prevention

When it happens

Trigger: Config written with a verbose or differently-cased permission word: mode: read-only, mode: readwrite, mode: w, or mode omitted entirely (empty string fails because "" is neither ro nor rw). The comparison is exact: no trimming, no case folding.

Common situations: Translating docker-compose volume options (rw/ro vs z/Z, consistent) or Kubernetes mount options into picoclaw config; users writing "read-only" out of habit; YAML quoting a value with a trailing space.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/4170b7266c6ac6d2. Report an issue: GitHub.