{"record":{"id":"4170b7266c6ac6d2","repo":"sipeed/picoclaw","slug":"invalid-expose-paths-mode-s","errorCode":null,"errorMessage":"invalid expose_paths mode: %s","messagePattern":"invalid expose_paths mode: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/isolation/runtime.go","lineNumber":170,"sourceCode":"\t}\n\n\tenv := make([]string, 0, len(envMap))\n\tfor k, v := range envMap {\n\t\tenv = append(env, fmt.Sprintf(\"%s=%s\", k, v))\n\t}\n\tcmd.Env = env\n}\n\n// ValidateExposePaths verifies the user-supplied path exposure rules before a\n// child process is started.\nfunc ValidateExposePaths(items []config.ExposePath) error {\n\tseen := map[string]struct{}{}\n\tfor _, item := range items {\n\t\tif item.Source == \"\" {\n\t\t\treturn fmt.Errorf(\"source is required\")\n\t\t}\n\t\tif item.Mode != \"ro\" && item.Mode != \"rw\" {\n\t\t\treturn fmt.Errorf(\"invalid expose_paths mode: %s\", item.Mode)\n\t\t}\n\n\t\tsource := filepath.Clean(item.Source)\n\t\ttarget := item.Target\n\t\tif target == \"\" {\n\t\t\ttarget = source\n\t\t}\n\t\ttarget = filepath.Clean(target)\n\n\t\tif !filepath.IsAbs(source) || !filepath.IsAbs(target) {\n\t\t\treturn fmt.Errorf(\"source and target must be absolute paths\")\n\t\t}\n\t\tif _, ok := seen[target]; ok {\n\t\t\treturn fmt.Errorf(\"duplicate expose_path target: %s\", target)\n\t\t}\n\t\tseen[target] = struct{}{}\n\t}\n\treturn nil","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/isolation/runtime.go#L152-L188","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use exactly ro or rw, lowercase, no whitespace","If you copied options from another tool's volume syntax, strip its extras (z, Z, shared, etc.)","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"],"exampleFix":"# before\nisolation:\n  expose_paths:\n    - source: /home/me/project\n      mode: read-only\n\n# after\nisolation:\n  expose_paths:\n    - source: /home/me/project\n      mode: ro","handlingStrategy":"type-guard","validationCode":"for _, p := range cfg.Isolation.ExposePaths {\n    if !isValidExposeMode(p.Mode) {\n        return fmt.Errorf(\"expose_paths mode must be exactly \\\"ro\\\" or \\\"rw\\\", got %q\", p.Mode)\n    }\n}","typeGuard":"func isValidExposeMode(mode string) bool {\n    return mode == \"ro\" || mode == \"rw\"\n}","tryCatchPattern":null,"preventionTips":["Accept only the literal lowercase tokens ro/rw in docs and generators","Do not port docker/Kubernetes volume flags verbatim — translate them to ro/rw first"],"tags":["config","validation","expose-paths"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}