{"record":{"id":"e6150bafd41305da","repo":"siyuan-note/siyuan","slug":"install-local-marketplace-package-failed-w-roll","errorCode":null,"errorMessage":"install local marketplace package failed: %w; rollback failed: %s","messagePattern":"install local marketplace package failed: %w; rollback failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/bazaar/install.go","lineNumber":219,"sourceCode":"\tdefer func() {\n\t\tif !preserveOperationPath {\n\t\t\t_ = os.RemoveAll(operationPath)\n\t\t}\n\t}()\n\tif err = filelock.Copy(sourcePath, stagingPath); err != nil {\n\t\treturn\n\t}\n\n\tif update {\n\t\tif err = os.Rename(installPath, backupPath); err != nil {\n\t\t\treturn\n\t\t}\n\t}\n\tif err = os.Rename(stagingPath, installPath); err != nil {\n\t\tif update {\n\t\t\tif rollbackErr := os.Rename(backupPath, installPath); rollbackErr != nil {\n\t\t\t\tpreserveOperationPath = true\n\t\t\t\treturn fmt.Errorf(\"install local marketplace package failed: %w; rollback failed: %s\", err, rollbackErr)\n\t\t\t}\n\t\t}\n\t\treturn\n\t}\n\tif update {\n\t\tif removeErr := os.RemoveAll(operationPath); removeErr != nil {\n\t\t\tlogging.LogWarnf(\"remove local package backup [%s] failed: %s\", backupPath, removeErr)\n\t\t}\n\t}\n\n\tRemoveInstalledPackageSizeCache(pkgType, packageName)\n\tnow := time.Now()\n\trecordPackageOperationTime(pkgType, packageName, now, fallbackInstallTime, update)\n\tif chtimesErr := os.Chtimes(installPath, now, now); chtimesErr != nil {\n\t\tlogging.LogWarnf(\"set package [%s] folder mtime failed: %s\", packageName, chtimesErr)\n\t}\n\treturn\n}","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/bazaar/install.go#L201-L237","documentation":"Returned by InstallLocalPackage (kernel/bazaar/install.go:215-219) during an update operation (update == true) when the atomic rename of stagingPath to installPath fails AND the subsequent rollback rename of backupPath to installPath also fails. This is a double-failure: the primary install failed and recovery failed too. The preserveOperationPath flag is set to true so the operation directory (containing both staging and backup) is NOT cleaned up by the deferred RemoveAll, leaving it for manual recovery. The error message includes both the primary error (%w) and the rollback error (%s).","triggerScenarios":"Calling InstallLocalPackage with update=true, where the final os.Rename(staging, install) fails (e.g. another process holds a lock on installPath) and the rollback os.Rename(backup, install) also fails.","commonSituations":"Antivirus or file indexer locking the install directory during rename on Windows; disk full preventing rename; filesystem corruption; another SiYuan instance or process accessing the package directory concurrently; permission issues on the parent directory.","solutions":["Close other applications that may be accessing the package directory (antivirus, file managers, other SiYuan instances)","Check available disk space on the target volume","Inspect the preserved operation directory (.siyuan-package-install-*) — it contains both staging and backup, allowing manual recovery","Check filesystem permissions on the install path and its parent","On Windows, try again after temporarily disabling antivirus real-time scanning for the SiYuan data directory"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"func checkInstallPathWritable(installPath string) error {\n    parent := filepath.Dir(installPath)\n    testFile := filepath.Join(parent, \".siyuan-write-test-\"+gulu.Rand.String(7))\n    if err := os.WriteFile(testFile, []byte(\"test\"), 0644); err != nil {\n        return fmt.Errorf(\"install directory is not writable: %w\", err)\n    }\n    os.Remove(testFile)\n    return nil\n}","typeGuard":null,"tryCatchPattern":"err := bazaar.InstallLocalPackage(sourcePath, installPath, pkgType, packageName, true)\nif err != nil {\n    if strings.Contains(err.Error(), \"rollback failed\") {\n        // Critical: the operation directory is preserved at .siyuan-package-install-*\n        // Log the path for manual recovery and alert the user\n        logging.LogErrorf(\"install + rollback failed: %v — operation dir preserved for manual recovery\", err)\n    }\n    return err\n}","preventionTips":["Ensure no other process (antivirus, file indexer, second SiYuan instance) locks the install directory during updates","Verify sufficient disk space before updating packages","On Windows, consider temporarily disabling real-time antivirus scanning for the SiYuan data directory","Check filesystem permissions on the package install path before initiating updates"],"tags":["bazaar","marketplace","install","filesystem","atomic-rename","recovery","go"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}