{"record":{"id":"f5f6a77a2f8d444f","repo":"chenhg5/cc-connect","slug":"resolve-home-dir-w","errorCode":null,"errorMessage":"resolve home dir: %w","messagePattern":"resolve home dir: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/wps-agentspace/wpsagentspace.go","lineNumber":269,"sourceCode":"\t\tname = \"image_\" + time.Now().Format(\"20060102_150405\") + ext\n\t}\n\n\tpath, err := p.saveAttachment(name, img.Data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"wps-agentspace: SendImage: %w\", err)\n\t}\n\n\tnotice := fmt.Sprintf(\"🖼 图片已保存到本地：\\n%s\", path)\n\treturn p.sendText(rc.ChatID, notice, rc)\n}\n\n// saveAttachment writes data to ~/.cc-connect/attachments/<name> and returns\n// the absolute path. The filename is sanitized to a basename to prevent path\n// traversal.\nfunc (p *Platform) saveAttachment(name string, data []byte) (string, error) {\n\thome, err := os.UserHomeDir()\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"resolve home dir: %w\", err)\n\t}\n\tdir := filepath.Join(home, \".cc-connect\", \"attachments\")\n\tif err := os.MkdirAll(dir, 0o755); err != nil {\n\t\treturn \"\", fmt.Errorf(\"mkdir: %w\", err)\n\t}\n\n\tname = filepath.Base(name)\n\tif name == \"\" || name == \".\" || name == \"/\" {\n\t\tname = fmt.Sprintf(\"file_%d\", time.Now().UnixMilli())\n\t}\n\tpath := filepath.Join(dir, name)\n\tif err := os.WriteFile(path, data, 0o644); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write: %w\", err)\n\t}\n\treturn path, nil\n}\n\n// Stop gracefully shuts down the platform.","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wps-agentspace/wpsagentspace.go#L251-L287","documentation":"saveAttachment calls os.UserHomeDir() and wraps its failure as \"resolve home dir: %w\". os.UserHomeDir returns an error when neither $HOME (Unix) nor the Windows user-profile APIs yield a home directory, so the platform cannot compute ~/.cc-connect/attachments and the attachment save aborts.","triggerScenarios":"Any call to SendFile or SendImage while the process has no resolvable home directory: $HOME unset/empty on Unix, or the Windows profile lookup failing (e.g. unusual service accounts).","commonSituations":"Daemonizing via systemd/init without setting HOME; running under docker with HOME unset or set to /nonexistent; running as a Windows service account without a loaded profile; launching from a stripped cron environment.","solutions":["Set HOME explicitly in the service environment (systemd: Environment=HOME=/home/ccconnect or /var/lib/cc-connect; docker: -e HOME=/home/app).","Run the daemon as a regular user that has a home directory, or create one with useradd -m.","As a caller, pre-check home resolution and fail fast with a clear config error before starting the platform."],"exampleFix":"// before: launching daemon with scrubbed env\ncmd := exec.Command(\"cc-connect\")\ncmd.Env = []string{\"PATH=/usr/bin\"}\n// after\ncmd := exec.Command(\"cc-connect\")\ncmd.Env = append(os.Environ(), \"HOME=/var/lib/cc-connect\")","handlingStrategy":"validation","validationCode":"home, err := os.UserHomeDir()\nif err != nil || home == \"\" {\n    return errors.New(\"HOME is not set; configure HOME for the cc-connect process\")\n}\nif fi, err := os.Stat(home); err != nil || !fi.IsDir() {\n    return fmt.Errorf(\"HOME %s is not an existing directory\", home)\n}","typeGuard":null,"tryCatchPattern":"if _, err := p.SendFile(rc, file); err != nil && strings.Contains(err.Error(), \"resolve home dir\") {\n    slog.Error(\"fix environment: set HOME for the daemon user\", \"err\", err)\n}","preventionTips":["Set Environment=HOME=... in systemd units or export HOME in container/cron entrypoints.","Avoid scrubbing os.Environ() when spawning the daemon.","On Windows service accounts, verify a user profile is loaded before starting the platform.","Add a startup self-check that fails fast if os.UserHomeDir() errors."],"tags":["go","home-directory","environment","attachments"],"backgroundTag":"missing-env-var","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"}