{"record":{"id":"5bb934be99a0b7f1","repo":"siyuan-note/siyuan","slug":"errlocalbazaarpackageexists","errorCode":"ErrLocalBazaarPackageExists","errorMessage":"marketplace package already exists","messagePattern":"marketplace package already exists","errorType":"error_code","errorClass":"ErrLocalBazaarPackageExists","httpStatus":null,"severity":"warning","filePath":"kernel/model/bazaar.go","lineNumber":110,"sourceCode":"\tmeta installMeta\n}\n\n// ThemeInstallOptions 描述新安装主题后需要应用的外观模式\ntype ThemeInstallOptions struct {\n\tMode   int\n\tModeOS bool\n}\n\n// LocalBazaarPackageInstallResult 描述本地集市包的识别和安装结果。\ntype LocalBazaarPackageInstallResult struct {\n\tPackageType   string `json:\"packageType\"`\n\tPackageName   string `json:\"packageName\"`\n\tMinAppVersion string `json:\"minAppVersion,omitempty\"`\n\tUpdated       bool   `json:\"updated\"`\n}\n\nvar (\n\tErrLocalBazaarPackageExists       = errors.New(\"marketplace package already exists\")\n\tErrLocalBazaarPackageIncompatible = errors.New(\"marketplace package is incompatible\")\n\tlocalBazaarInstallLock            sync.Mutex\n)\n\n// updatePackages 更新一组集市包；同类型批量更新时，安装后处理只执行一次\nfunc updatePackages(packages []*UpdatedPackage, pkgType string, successCount, failedCount *int, planned int) {\n\titems := make([]batchInstallItem, 0, len(packages))\n\tfor _, updated := range packages {\n\t\tpkg := updated.Available\n\t\tmeta, err := installBazaarPackage(pkgType, pkg.RepoURL, pkg.RepoHash, pkg.Name)\n\t\tif err != nil {\n\t\t\tlogging.LogErrorf(\"update %s [%s] failed: %s\", pkgType, pkg.Name, err)\n\t\t\tutil.PushErrMsg(fmt.Sprintf(Conf.language(238), pkg.Name), 5000)\n\t\t\t*failedCount++\n\t\t\tcontinue\n\t\t}\n\t\titems = append(items, batchInstallItem{name: pkg.Name, meta: meta})\n\t\t*successCount++","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/bazaar.go#L92-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["If you intend to replace the existing package, retry the install with overwrite=true.","If you did not expect a duplicate, uninstall the existing package first, then install.","Check errors.Is(err, model.ErrLocalBazaarPackageExists) to surface a 'replace?' prompt in the UI."],"exampleFix":"// before\nresult, err := model.InstallLocalBazaarPackage(archivePath, frontend, false)\n// after (if replacement is intended)\nresult, err := model.InstallLocalBazaarPackage(archivePath, frontend, true)","handlingStrategy":"validation","validationCode":"// Pre-check existence and decide whether to overwrite.\n_, statErr := os.Lstat(installPath)\nif statErr == nil && !overwrite {\n    // surface a 'package already exists, replace?' prompt instead of failing\n}","typeGuard":null,"tryCatchPattern":"result, err := model.InstallLocalBazaarPackage(archivePath, frontend, overwrite)\nif err != nil {\n    if errors.Is(err, model.ErrLocalBazaarPackageExists) {\n        // prompt user to confirm overwrite, then retry with overwrite=true\n        result, err = model.InstallLocalBazaarPackage(archivePath, frontend, true)\n    }\n}","preventionTips":["Check whether the target package directory exists before installing.","Use errors.Is against the sentinel ErrLocalBazaarPackageExists to drive a replace prompt.","Make overwrite an explicit user decision in the UI."],"tags":["bazaar","package-management","conflict","sentinel-error"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}