{"record":{"id":"088b46869b54c755","repo":"siyuan-note/siyuan","slug":"invalid-package-type","errorCode":null,"errorMessage":"invalid package type","messagePattern":"invalid package type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/bazaar.go","lineNumber":74,"sourceCode":"\tif !isValidPackageName(packageName) {\n\t\treturn \"\", \"\", errors.New(\"invalid package name\")\n\t}\n\n\tvar baseDir, jsonFileName string\n\tswitch pkgType {\n\tcase \"plugins\":\n\t\tbaseDir, jsonFileName = filepath.Join(util.DataDir, \"plugins\"), \"plugin.json\"\n\tcase \"themes\":\n\t\tbaseDir, jsonFileName = util.ThemesPath, \"theme.json\"\n\tcase \"icons\":\n\t\tbaseDir, jsonFileName = util.IconsPath, \"icon.json\"\n\tcase \"templates\":\n\t\tbaseDir, jsonFileName = filepath.Join(util.DataDir, \"templates\"), \"template.json\"\n\tcase \"widgets\":\n\t\tbaseDir, jsonFileName = filepath.Join(util.DataDir, \"widgets\"), \"widget.json\"\n\tdefault:\n\t\tlogging.LogErrorf(\"invalid package type: %s\", pkgType)\n\t\treturn \"\", \"\", errors.New(\"invalid package type\")\n\t}\n\n\tinstallPath := filepath.Join(baseDir, packageName)\n\tif !gulu.File.IsSubPath(baseDir, installPath) {\n\t\treturn \"\", \"\", errors.New(\"invalid package name\")\n\t}\n\treturn installPath, jsonFileName, nil\n}\n\n// installMeta 记录安装前后的状态，供安装后处理使用\ntype installMeta struct {\n\tupdate bool\n}\n\n// batchInstallItem 同类型批量安装时单个包的结果\ntype batchInstallItem struct {\n\tname string\n\tmeta installMeta","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/bazaar.go#L56-L92","documentation":"Thrown by getPackageInstallPath when pkgType is not one of the five supported kinds: plugins, themes, icons, templates, widgets. The switch has no other cases, so any other string reaches the default branch. The invalid value is logged via logging.LogErrorf before the error is returned.","triggerScenarios":"Calling any install-path-dependent bazaar function (InstallBazaarPackage, InstallLocalBazaarPackage, UpdateBazaarPackage, getPackageUninstallPath, GetInstalledPackageSize) with a pkgType outside the allowed set, e.g. 'extensions', 'snippets', a typo like 'plugin', or an empty string.","commonSituations":"A frontend or integration hardcoding a package type that does not exist, a typo, or a plugin using a stale constant after a rename. Also triggered by malformed API requests.","solutions":["Use one of the exact strings: 'plugins', 'themes', 'icons', 'templates', 'widgets'.","Centralize pkgType constants in the caller instead of string literals to avoid typos.","Validate pkgType against the allowlist before issuing the request."],"exampleFix":"// before\ninstallPackage(\"plugin\", name) // typo\n// after\ninstallPackage(\"plugins\", name)","handlingStrategy":"validation","validationCode":"var validPkgTypes = map[string]bool{\"plugins\": true, \"themes\": true, \"icons\": true, \"templates\": true, \"widgets\": true}\nif !validPkgTypes[pkgType] {\n    return fmt.Errorf(\"invalid package type: %q\", pkgType)\n}","typeGuard":"func isValidPkgType(t string) bool {\n    switch t {\n    case \"plugins\", \"themes\", \"icons\", \"templates\", \"widgets\":\n        return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Centralize package-type constants in a single shared map or const block.","Validate pkgType at the API boundary before dispatching to install/path functions.","Add a unit test that asserts the allowlist matches both switch statements."],"tags":["bazaar","package-management","input-validation","enum"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}