siyuan-note/siyuan · warning · ErrLocalBazaarPackageExists
marketplace package already exists
Error message
marketplace package already exists
What it means
Sentinel error ErrLocalBazaarPackageExists returned by model.InstallLocalBazaarPackage (kernel/model/bazaar.go) when installing a local marketplace package whose install path already exists on disk (os.Lstat succeeds, so result.Updated is true) and the caller passed overwrite=false. It protects an already-installed plugin/theme/icon/widget/template from being silently replaced by an imported archive. It is a deliberate, recoverable refusal, not a defect: the UI is expected to catch it and ask the user whether to overwrite.
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 afa823b6b4)
Solutions
- Pass overwrite=true in the InstallLocalBazaarPackage call when the user confirmed replacing the existing package (the result.Updated flag then drives update semantics such as plugin reload instead of fresh install)
- Uninstall the existing package first (model.UninstallPackage) and then import with overwrite=false
- If the leftover directory is from a failed uninstall, remove it manually from data/plugins/<name> (or the matching themes/icons/widgets/templates folder) and retry the import
Example fix
// before
result, err := model.InstallLocalBazaarPackage(archivePath, frontend, false)
if err != nil {
return err // surfaces "marketplace package already exists"
}
// after
result, err := model.InstallLocalBazaarPackage(archivePath, frontend, false)
if errors.Is(err, model.ErrLocalBazaarPackageExists) {
// ask the user, then retry with overwrite=true
result, err = model.InstallLocalBazaarPackage(archivePath, frontend, true)
}
if err != nil {
return err
} Defensive patterns
Strategy: validation
Validate before calling
infos, _, _, err := model.GetInstalledPackageInfos(pkgType)
if err != nil {
return err
}
exists := false
for _, info := range infos {
if info.Pkg.Name == pkgName {
exists = true
break
}
}
if exists && !userConfirmedOverwrite {
return errors.New("ask user: overwrite existing package?")
} Type guard
func isPackageExistsErr(err error) bool {
return errors.Is(err, model.ErrLocalBazaarPackageExists)
} Try / catch
result, err := model.InstallLocalBazaarPackage(archivePath, frontend, false)
if err != nil {
if errors.Is(err, model.ErrLocalBazaarPackageExists) {
// prompt user; on confirm retry with overwrite=true
}
return err
} Prevention
- Always pass overwrite=false on first attempt and treat ErrLocalBazaarPackageExists as a prompt, not a failure
- Check GetInstalledPackageInfos before importing so the UI can offer 'update' instead of 'install' semantics
When it happens
Trigger: Calling model.InstallLocalBazaarPackage(archivePath, frontend, false) for a package whose directory already exists under data/plugins/, data/widgets/, data/templates/, appearance/themes/, or appearance/icons/ (e.g. re-importing a theme zip that is already installed). Any HTTP handler for local package import that forwards overwrite=false hits it whenever the package name resolves to an existing install path.
Common situations: User downloads a theme/plugin zip and imports it while an older copy is still installed; reinstalling a package after a failed uninstall left the directory behind; importing a package whose manifest name field collides with an installed one.
Related errors
- multiple marketplace package manifests found
- marketplace package manifest not found
- invalid marketplace package manifest
- invalid marketplace package archive
- marketplace package archive is empty
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/b82dc07fe782aab5.
Report an issue: GitHub.