{"record":{"id":"dc8499d37edcb5e4","repo":"chenhg5/cc-connect","slug":"mkdir-w","errorCode":null,"errorMessage":"mkdir: %w","messagePattern":"mkdir: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/wps-agentspace/wpsagentspace.go","lineNumber":273,"sourceCode":"\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.\nfunc (p *Platform) Stop() error {\n\tp.stopOnce.Do(func() {\n\t\tp.stopped.Store(true)\n\t\tif p.cancel != nil {","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/wps-agentspace/wpsagentspace.go#L255-L291","documentation":"saveAttachment creates ~/.cc-connect/attachments with os.MkdirAll(dir, 0o755) and wraps failures as \"mkdir: %w\". This fires when the directory tree cannot be created or already exists as a non-directory, typically due to permissions or filesystem state, and aborts SendFile/SendImage.","triggerScenarios":"SendFile or SendImage when: $HOME is read-only or owned by another user; a component of the path (~/.cc-connect or ~/.cc-connect/attachments) exists as a regular file; the filesystem is read-only or full; SELinux/AppArmor denies the write.","commonSituations":"Container images with read-only rootfs; daemons running as non-root users while ~/.cc-connect was created by root during manual testing; macOS sandboxed launchd contexts; immutable infrastructure mounts.","solutions":["Inspect the wrapped errno with errors.Is(err, os.ErrPermission) / syscall.ENOTDIR / ENOSPC to identify the exact cause.","Fix ownership/permissions: chown -R the daemon user ~/.cc-connect, or chmod u+rwx on each path component.","If ~/.cc-connect exists as a file, remove or rename it so the directory can be created.","Mount a writable volume at ~/.cc-connect (or set HOME to a writable path) in containers."],"exampleFix":"// before: diagnose only from generic failure\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return \"\", fmt.Errorf(\"mkdir: %w\", err)\n}\n// after (caller-side guard)\nif fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"mkdir: %w\", err)\n}","handlingStrategy":"validation","validationCode":"dir := filepath.Join(home, \".cc-connect\", \"attachments\")\nif fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s exists but is not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"cannot create %s: %w\", dir, err)\n}","typeGuard":null,"tryCatchPattern":"if _, err := p.SendFile(rc, file); err != nil && strings.HasPrefix(err.Error(), \"mkdir:\") {\n    var pe *fs.PathError\n    if errors.As(err, &pe) && errors.Is(pe.Err, os.ErrPermission) {\n        slog.Error(\"permission denied creating attachments dir\", \"path\", pe.Path)\n    }\n}","preventionTips":["Ensure no regular file occupies ~/.cc-connect or ~/.cc-connect/attachments.","Run the daemon as the same user that owns $HOME; avoid mixing root and user runs.","In containers, mount a writable volume for the attachments directory or use a read-write rootfs.","Check SELinux/AppArmor policies allow the daemon user to write under $HOME."],"tags":["go","mkdir","permissions","filesystem"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}