siyuan-note/siyuan · error

marketplace package install path already exists

Error message

marketplace package install path already exists

What it means

Returned by installPackage (kernel/bazaar/install.go:129-136) during a fresh install (update == false) when the target installPath directory already exists and contains one or more entries. This is a deliberate security guard (GHSA-rpx2-p6hp-x5gj) to prevent a newly downloaded package from silently overwriting files in an already-populated directory, which could be exploited to inject malicious content into an existing package.

Source

Thrown at kernel/bazaar/install.go:135

	// 文件夹的修改时间设置为当前操作时间
	if err = os.Chtimes(installPath, now, now); err != nil {
		logging.LogWarnf("set package [%s] folder mtime failed: %s", packageName, err)
	}

	go incPackageDownloads(repoURL, systemID)
	return nil
}

func installPackage(data []byte, installPath, pkgType, packageName string, update bool) (err error) {
	// 非更新安装时目标目录已存在且非空则拒绝覆盖,防止把其他包的内容写入已有包目录
	// https://github.com/siyuan-note/siyuan/security/advisories/GHSA-rpx2-p6hp-x5gj
	if !update {
		entries, statErr := os.ReadDir(installPath)
		if statErr != nil && !os.IsNotExist(statErr) {
			return statErr
		}
		if 0 < len(entries) {
			return errors.New("marketplace package install path already exists")
		}
	}

	tmpPackage := filepath.Join(util.TempDir, "bazaar", "package")
	if err = os.MkdirAll(tmpPackage, 0755); err != nil {
		return
	}
	name := gulu.Rand.String(7)
	tmp := filepath.Join(tmpPackage, name+".zip")
	defer os.RemoveAll(tmp)
	if err = os.WriteFile(tmp, data, 0644); err != nil {
		return
	}

	unzipPath := filepath.Join(tmpPackage, name)
	defer os.RemoveAll(unzipPath)
	if err = gulu.Zip.Unzip(tmp, unzipPath); err != nil {
		logging.LogErrorf("write file [%s] failed: %s", installPath, err)

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Uninstall the existing package first via UninstallPackage, then retry the fresh install
  2. If updating an existing package, call InstallPackage with update=true instead of false
  3. Manually remove the install directory if it contains only leftover/empty files
  4. Check for package name collisions — ensure two packages don't share the same install path

Example fix

// before: fresh install over existing directory
bazaar.InstallPackage(repoURL, repoHash, installPath, systemID, pkgType, pkgName, false)
// after: uninstall first, then install
bazaar.UninstallPackage(installPath)
bazaar.InstallPackage(repoURL, repoHash, installPath, systemID, pkgType, pkgName, false)
Defensive patterns

Strategy: validation

Validate before calling

func ensureInstallPathAvailable(installPath string, update bool) error {
    if update {
        return nil
    }
    entries, err := os.ReadDir(installPath)
    if err != nil && !os.IsNotExist(err) {
        return err
    }
    if len(entries) > 0 {
        return fmt.Errorf("path %s already exists and is non-empty — uninstall first or use update mode", installPath)
    }
    return nil
}

Prevention

When it happens

Trigger: Calling InstallPackage with update=false for a package whose install directory (e.g. data/plugins/<name>) already exists and is non-empty.

Common situations: Reinstalling a package that was partially uninstalled (directory left behind); package name collision between two different packages; a previous install left residual files; attempting to install over a manually placed package.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/107e366f9fca7ef3. Report an issue: GitHub.