siyuan-note/siyuan · warning · ErrLocalBazaarPackageExists

ErrLocalBazaarPackageExists

ErrLocalBazaarPackageExists

Error message

marketplace package already exists

What it means

Sentinel error ErrLocalBazaarPackageExists, returned by InstallLocalBazaarPackage when the target install path already exists (os.Lstat succeeds, so result.Updated is true) but the caller did not pass overwrite=true. It is a soft conflict: the package is present and the user must explicitly choose to replace it.

Source

Thrown at kernel/model/bazaar.go:110

	meta installMeta
}

// ThemeInstallOptions 描述新安装主题后需要应用的外观模式
type ThemeInstallOptions struct {
	Mode   int
	ModeOS bool
}

// LocalBazaarPackageInstallResult 描述本地集市包的识别和安装结果。
type LocalBazaarPackageInstallResult struct {
	PackageType   string `json:"packageType"`
	PackageName   string `json:"packageName"`
	MinAppVersion string `json:"minAppVersion,omitempty"`
	Updated       bool   `json:"updated"`
}

var (
	ErrLocalBazaarPackageExists       = errors.New("marketplace package already exists")
	ErrLocalBazaarPackageIncompatible = errors.New("marketplace package is incompatible")
	localBazaarInstallLock            sync.Mutex
)

// updatePackages 更新一组集市包;同类型批量更新时,安装后处理只执行一次
func updatePackages(packages []*UpdatedPackage, pkgType string, successCount, failedCount *int, planned int) {
	items := make([]batchInstallItem, 0, len(packages))
	for _, updated := range packages {
		pkg := updated.Available
		meta, err := installBazaarPackage(pkgType, pkg.RepoURL, pkg.RepoHash, pkg.Name)
		if err != nil {
			logging.LogErrorf("update %s [%s] failed: %s", pkgType, pkg.Name, err)
			util.PushErrMsg(fmt.Sprintf(Conf.language(238), pkg.Name), 5000)
			*failedCount++
			continue
		}
		items = append(items, batchInstallItem{name: pkg.Name, meta: meta})
		*successCount++

View on GitHub (pinned to 251596fc0d)

Solutions

  1. If you intend to replace the existing package, retry the install with overwrite=true.
  2. If you did not expect a duplicate, uninstall the existing package first, then install.
  3. Check errors.Is(err, model.ErrLocalBazaarPackageExists) to surface a 'replace?' prompt in the UI.

Example fix

// before
result, err := model.InstallLocalBazaarPackage(archivePath, frontend, false)
// after (if replacement is intended)
result, err := model.InstallLocalBazaarPackage(archivePath, frontend, true)
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check existence and decide whether to overwrite.
_, statErr := os.Lstat(installPath)
if statErr == nil && !overwrite {
    // surface a 'package already exists, replace?' prompt instead of failing
}

Try / catch

result, err := model.InstallLocalBazaarPackage(archivePath, frontend, overwrite)
if err != nil {
    if errors.Is(err, model.ErrLocalBazaarPackageExists) {
        // prompt user to confirm overwrite, then retry with overwrite=true
        result, err = model.InstallLocalBazaarPackage(archivePath, frontend, true)
    }
}

Prevention

When it happens

Trigger: Uploading and installing a local package (archive) whose name already corresponds to an installed package directory, without setting the overwrite flag in the install-local API call.

Common situations: Reinstalling or re-importing a plugin/theme/icon that is already on disk; or a user double-triggering the install. The previous install is intact, so this is recoverable without data loss.

Related errors


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