{"record":{"id":"b8f35df1da954f05","repo":"chenhg5/cc-connect","slug":"project-q-target-user-q-cannot-read-and-write-w","errorCode":null,"errorMessage":"project %q: target user %q cannot read AND write work_dir %q. Agents will fail with EACCES at runtime. Fix ownership/permissions on this directory (chown/chmod or an ACL granting the target user rwx) before starting cc-connect.","messagePattern":"project %q: target user %q cannot read AND write work_dir %q\\. Agents will fail with EACCES at runtime\\. Fix ownership/permissions on this directory \\(chown/chmod or an ACL granting the target user rwx\\) before starting cc-connect\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"core/runas_check.go","lineNumber":128,"sourceCode":"\t\t\tcfg.Project, cfg.RunAsUser)\n\t\tif result.SudoListOutput != \"\" {\n\t\t\tmsg += \"\\n\\n`sudo -n -l` as \" + cfg.RunAsUser + \":\\n\" + indent(result.SudoListOutput, \"  \")\n\t\t}\n\t\tresult.Fatal = append(result.Fatal, errors.New(msg))\n\t\t// Don't return — still run check 3 so the operator gets all\n\t\t// the bad news in a single startup attempt.\n\t}\n\n\tif cfg.WorkDir == \"\" {\n\t\tresult.Warnings = append(result.Warnings, fmt.Sprintf(\n\t\t\t\"project %q: no work_dir configured; skipping filesystem access checks\", cfg.Project))\n\t} else {\n\t\tabsWorkDir := cfg.WorkDir\n\t\tif abs, err := filepath.Abs(absWorkDir); err == nil {\n\t\t\tabsWorkDir = abs\n\t\t}\n\t\tif _, err := cfg.Runner.Run(ctx, \"-n\", \"-iu\", cfg.RunAsUser, \"--\", \"test\", \"-r\", absWorkDir, \"-a\", \"-w\", absWorkDir); err != nil {\n\t\t\tresult.Fatal = append(result.Fatal, fmt.Errorf(\n\t\t\t\t\"project %q: target user %q cannot read AND write work_dir %q. Agents will fail with EACCES at runtime. Fix ownership/permissions on this directory (chown/chmod or an ACL granting the target user rwx) before starting cc-connect.\",\n\t\t\t\tcfg.Project, cfg.RunAsUser, absWorkDir))\n\t\t} else {\n\t\t\twarn := scanDescendants(ctx, cfg.Runner, cfg.RunAsUser, absWorkDir, cfg.ScanConfig)\n\t\t\tif warn != \"\" {\n\t\t\t\tresult.Warnings = append(result.Warnings, warn)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result\n}\n\n// scanDescendants runs find as the target user under workDir and\n// returns a formatted warning string, or \"\" if nothing is flagged.\n// Respects ScanConfig.Timeout. Output format per line is\n// \"MODE<TAB>PATH\" where MODE is noread / nowrite / nosearch.\nfunc scanDescendants(ctx context.Context, runner SudoRunner, target, workDir string, scan DescendantScanConfig) string {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/runas_check.go#L110-L146","documentation":"PreflightRunAsUser (core/runas_check.go:128) checks that the run-as target user can both read and write cfg.WorkDir by running 'sudo -n -iu <user> -- test -r <dir> -a -w <dir>'. Failure means ownership/permissions are wrong and the agent would hit EACCES at runtime, so it is recorded as a fatal startup error with remediation guidance.","triggerScenarios":"The work_dir is owned by root or another user, has mode without rwx for the target (e.g. 0750 root:root), lacks the execute bit needed to traverse, or sits under a parent directory the target user cannot traverse. Raised during doctor/preflight when the test -r -a -w probe exits non-zero.","commonSituations":"Directory created by root during provisioning with restrictive umask; work_dir owned by the supervisor instead of the agent user; project path moved and ownership not migrated; container volume mounted root-owned.","solutions":["chown the work_dir to the target user: sudo chown -R <run_as_user> <work_dir>","Or grant rwx via chmod (e.g. chmod 770 with a shared group) or a POSIX ACL: setfacl -R -m u:<run_as_user>:rwx <work_dir>","Ensure every parent directory grants the target user traverse (x) permission","Re-run the check: sudo -n -iu <user> -- test -r <dir> -a -w <dir> && echo ok","Re-run cc-connect doctor to confirm the fatal is gone"],"exampleFix":"// before\nsudo mkdir -p /srv/work && sudo tar -xzf proj.tgz -C /srv/work   # root-owned, 0755\n// agent fails preflight: cannot read AND write work_dir\n// after\nsudo chown -R agent1:agent1 /srv/work","handlingStrategy":"validation","validationCode":"func workDirAccessible(target, dir string) error {\n\tabs, err := filepath.Abs(dir); if err != nil { return err }\n\tcmd := exec.Command(\"sudo\", \"-n\", \"-iu\", target, \"--\", \"test\", \"-r\", abs, \"-a\", \"-w\", abs)\n\tif err := cmd.Run(); err != nil { return fmt.Errorf(\"%s cannot r/w %s\", target, abs) }\n\treturn nil\n}\n// call before starting cc-connect with run_as_user","typeGuard":null,"tryCatchPattern":"result := core.PreflightRunAsUser(ctx, cfg)\nfor _, f := range result.Fatal {\n\tif strings.Contains(f.Error(), \"cannot read AND write work_dir\") {\n\t\tfmt.Fprintf(os.Stderr, \"FATAL (fix ownership/permissions, e.g. chown -R %s %s): %v\\n\", cfg.RunAsUser, cfg.WorkDir, f)\n\t\tos.Exit(1)\n\t}\n}","preventionTips":["Provision work_dir with the target user as owner at deploy time (chown -R <run_as_user>)","Remember parent directories need the x (traverse) bit for the target user","For shared dirs use group ownership or ACLs (setfacl -m u:<target>:rwx) instead of world-writable modes","Re-run preflight after moving projects or changing mounts/volumes"],"tags":["permissions","filesystem","runas","preflight","workdir"],"backgroundTag":"file-write-permission-denied","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}