{"record":{"id":"0573727e38ced4ba","repo":"github/copilot-sdk","slug":"creating-install-directory-w","errorCode":null,"errorMessage":"creating install directory: %w","messagePattern":"creating install directory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/internal/embeddedcli/embeddedcli.go","lineNumber":245,"sourceCode":"\tcfg.RuntimeAssetsHash = cfg.LinuxMuslRuntimeAssetsHash\n\treturn cfg\n}\n\nfunc isMusl() bool {\n\tout, _ := exec.Command(\"ldd\", \"--version\").CombinedOutput()\n\treturn strings.Contains(strings.ToLower(string(out)), \"musl\")\n}\n\nfunc installAt(installDir string) (string, error) {\n\tversion := sanitizeVersion(config.Version)\n\tif version != \"\" {\n\t\tinstallDir = filepath.Join(installDir, version)\n\t}\n\tif linuxMuslBundle {\n\t\tinstallDir = filepath.Join(installDir, \"linuxmusl\")\n\t}\n\tif err := os.MkdirAll(installDir, 0755); err != nil {\n\t\treturn \"\", fmt.Errorf(\"creating install directory: %w\", err)\n\t}\n\n\t// Best effort to prevent concurrent installs.\n\tif release, _ := flock.Acquire(filepath.Join(installDir, \".copilot-cli.lock\")); release != nil {\n\t\tdefer release()\n\t}\n\n\tbinaryName := \"copilot\"\n\tif runtime.GOOS == \"windows\" {\n\t\tbinaryName += \".exe\"\n\t}\n\tfinalPath := filepath.Join(installDir, binaryName)\n\n\tif _, err := os.Stat(finalPath); err == nil {\n\t\texistingHash, err := hashFile(finalPath)\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"hashing existing binary: %w\", err)\n\t\t}","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/internal/embeddedcli/embeddedcli.go#L227-L263","documentation":"installAt creates the versioned install directory (with MkdirAll) before laying down the CLI binary and assets. If directory creation fails, the error is wrapped with this message. It prevents installation from proceeding without a writable target directory.","triggerScenarios":"os.MkdirAll on the install path fails: parent dir not writable, path exists as a regular file, read-only filesystem, or SELinux/AppArmor denial.","commonSituations":"Installing into a system path like /usr/local/lib without sudo; install root pre-empted by a stale file with the same name; running in a read-only container filesystem; multi-user machines where another user owns the version directory.","solutions":["Check the wrapped err for the exact cause (EACCES, ENOTDIR, EROFS)","Create the parent install dir with proper ownership/permissions (sudo mkdir + chown) or point the install dir at a user-writable location (e.g. under $HOME)","If a file exists where the directory should be, remove or rename it","Avoid read-only filesystems, or install to a writable volume"],"exampleFix":"// before\n// installAt(\"/usr/local/lib/copilot\", ...) fails with permission denied\n// after\ndir := os.Getenv(\"XDG_DATA_HOME\")\nif dir == \"\" { dir = filepath.Join(os.Getenv(\"HOME\"), \".local\", \"share\") }\npath, err := installAt(filepath.Join(dir, \"copilot\"), version)","handlingStrategy":"try-catch","validationCode":"// verify the install root is writable before installing\nif err := os.MkdirAll(installRoot, 0755); err != nil { /* pick a writable dir */ }","typeGuard":null,"tryCatchPattern":"// Go\npath, err := installAt(dir, version)\nvar pe *fs.PathError\nif err != nil && errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission) {\n\t// fall back to a user-writable install location\n}","preventionTips":["Default installs under $HOME or XDG dirs instead of system paths","Check writability of the install root at startup","Never let a regular file occupy the install directory path"],"tags":["filesystem","install","permissions"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}