{"record":{"id":"0df4856d182366cc","repo":"flipped-aurora/gin-vue-admin","slug":"s-w-0df485","errorCode":null,"errorMessage":"原子发布 %s 失败: %w","messagePattern":"原子发布 (.+?) 失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/auto_code_task.go","lineNumber":209,"sourceCode":"\tcurrentHash, exists, err := hashAutoCodeTarget(file.TargetPath)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif exists && currentHash == file.AfterHash {\n\t\tif removeErr := os.Remove(file.StagedPath); removeErr != nil && !errors.Is(removeErr, fs.ErrNotExist) {\n\t\t\treturn false, fmt.Errorf(\"清理重复 staging 文件失败: %w\", removeErr)\n\t\t}\n\t\tfile.StagedPath = \"\"\n\t\treturn false, nil\n\t}\n\tif exists != file.Existed || (file.Existed && currentHash != file.BeforeHash) {\n\t\treturn false, fmt.Errorf(\"%w: %s\", errAutoCodeFileConflict, file.TargetPath)\n\t}\n\tif err = os.MkdirAll(filepath.Dir(file.TargetPath), 0o755); err != nil {\n\t\treturn false, fmt.Errorf(\"创建目标目录 %s 失败: %w\", filepath.Dir(file.TargetPath), err)\n\t}\n\tif err = os.Rename(file.StagedPath, file.TargetPath); err != nil {\n\t\treturn false, fmt.Errorf(\"原子发布 %s 失败: %w\", file.TargetPath, err)\n\t}\n\tfile.StagedPath = \"\"\n\treturn true, nil\n}\n\nfunc (task *autoCodeFileTask) rollback(applied []int) error {\n\tfor i := len(applied) - 1; i >= 0; i-- {\n\t\tindex := applied[i]\n\t\tif index < 0 || index >= len(task.files) {\n\t\t\treturn fmt.Errorf(\"自动代码回滚索引无效: %d\", index)\n\t\t}\n\t\tfile := &task.files[index]\n\t\tcurrentHash, exists, err := hashAutoCodeTarget(file.TargetPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif file.Existed && exists && currentHash == file.BeforeHash {\n\t\t\tcontinue","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/auto_code_task.go#L191-L227","documentation":"Raised when the final atomic publish step os.Rename(stagedPath, targetPath) fails. Staged content is written to a temp file in the project root and moved into place with rename for atomicity; rename failures abort the publish of that file and trigger rollback of already-published files.","triggerScenarios":"os.Rename fails with EXDEV (staging dir and target on different filesystems/mounts), permission denied on the target directory or existing target file, target became a directory, or the staged file was removed mid-task.","commonSituations":"web/ or server/ is a separate mount/symlink into another filesystem while the staging dir lives in the repo root (EXDEV); target file owned by root or another user; editors/watchers holding the target open with delete restrictions on some platforms; Docker volume boundary between staging and target.","solutions":["Ensure the repo root, server/ and web/ trees live on the same local filesystem (avoid mounting web/ on a different device than the root that hosts the staging dir)","Fix permissions on the target directory/existing file so the server process can replace it","Verify the target path is a regular file, not a directory","Re-run after closing processes that lock target files; check mount layout if EXDEV is reported"],"exampleFix":"// before: web on separate mount -> EXDEV on rename\n/dev/sdb1 on /project/web type ext4\n\n// after: keep web/ inside the repo root filesystem (same device as staging dir)\n$ mv /mnt/otherdisk/web ./web  # then regenerate/re-run","handlingStrategy":"validation","validationCode":"func sameDevice(a, b string) error {\n\taInfo, err := os.Stat(a)\n\tif err != nil {\n\t\treturn err\n\t}\n\tbInfo, err := os.Stat(b)\n\tif err != nil {\n\t\treturn err\n\t}\n\taSys, bSys := aInfo.Sys().(*syscall.Stat_t), bInfo.Sys().(*syscall.Stat_t)\n\tif aSys.Dev != bSys.Dev {\n\t\treturn fmt.Errorf(\"%s and %s on different devices (rename would fail with EXDEV)\", a, b)\n\t}\n\treturn nil\n}\n// check repo root (staging parent) vs each target's directory before committing","typeGuard":null,"tryCatchPattern":"if err := commitAutoCodeFileTask(task, publishPreparedAutoCodeFile, persist); err != nil {\n\tif strings.Contains(err.Error(), \"原子发布\") {\n\t\tvar pathErr *os.LinkError\n\t\tif errors.As(err, &pathErr) && errors.Is(pathErr, syscall.EXDEV) {\n\t\t\t// reconfigure layout so staging dir and targets share one filesystem\n\t\t}\n\t}\n}","preventionTips":["Keep the auto-code root, server/ and web/ on the same local filesystem","Avoid symlinking web/ or server/ into other mounts; the staging dir lives in the repo root","Ensure target files are regular files owned/writable by the service user","Close editors/build tools that may hold or replace target files during generation"],"tags":["filesystem","atomic-rename","exdev","autocode","file-publish"],"backgroundTag":"atomic-rename-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}