{"record":{"id":"a714188cf71665f2","repo":"siyuan-note/siyuan","slug":"update-package-url-or-checksum-is-empty","errorCode":null,"errorMessage":"update package URL or checksum is empty","messagePattern":"update package URL or checksum is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/updater.go","lineNumber":138,"sourceCode":"\t\treturn\n\t}\n\tpkg := release.Packages[pkgName]\n\tif nil == pkg || 0 == len(pkg.URLs) {\n\t\terr = fmt.Errorf(\"%w: [%s]\", errUpdatePackageUnavailable, pkgName)\n\t\treturn\n\t}\n\tif \"\" == pkg.Checksum {\n\t\terr = fmt.Errorf(\"%w: [%s] checksum is unavailable\", errUpdatePackageUnavailable, pkgName)\n\t\treturn\n\t}\n\tdownloadPkgURLs = append(downloadPkgURLs, pkg.URLs...)\n\tchecksum = pkg.Checksum\n\treturn\n}\n\nfunc downloadInstallPkg(pkgURL, checksum string) (err error) {\n\tif \"\" == pkgURL || \"\" == checksum {\n\t\terr = errors.New(\"update package URL or checksum is empty\")\n\t\treturn\n\t}\n\n\tpkg := path.Base(pkgURL)\n\tsavePath := filepath.Join(util.TempDir, \"install\", pkg)\n\tif gulu.File.IsExist(savePath) {\n\t\tlocalChecksum, _ := sha256Hash(savePath)\n\t\tif localChecksum == checksum {\n\t\t\treturn\n\t\t}\n\t}\n\n\terr = os.MkdirAll(filepath.Join(util.TempDir, \"install\"), 0755)\n\tif err != nil {\n\t\tlogging.LogErrorf(\"create temp install dir failed: %s\", err)\n\t\treturn\n\t}\n","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/updater.go#L120-L156","documentation":"Returned by downloadInstallPkg(pkgURL, checksum) at its entry guard when either pkgURL or checksum is an empty string. This is a defensive precondition check: the function refuses to start a download or trust a checksum-less file. In normal flow getUpdatePkg() guarantees both are non-empty before calling, so hitting this indicates a programming error in the caller.","triggerScenarios":"A caller bypasses getUpdatePkg() and invokes downloadInstallPkg(\"\", checksum) or downloadInstallPkg(url, \"\"). A refactor leaves a code path that passes unset/zero-value strings. The single internal call site (checkDownloadInstallPkg line 93) passes values sourced from getUpdatePkg, which already validated non-empties, so production hits are rare.","commonSituations":"Plugin or fork code that calls the downloader directly without re-validating. A code change that introduces a new call site but forgets to populate the URL or checksum.","solutions":["Ensure the caller validates both arguments are non-empty before invoking downloadInstallPkg.","Route package selection through getUpdatePkg(), which already enforces non-empty URLs and checksum.","Add a unit test asserting the precondition on any new call site."],"exampleFix":"// before\ndownloadInstallPkg(pkgURL, \"\") // panics-free but returns error, download never starts\n\n// after\nif \"\" == pkgURL || \"\" == checksum {\n    return fmt.Errorf(\"%w: url=%q checksum-set=%v\", errUpdatePackageUnavailable, pkgURL, checksum != \"\")\n}\ndownloadInstallPkg(pkgURL, checksum)","handlingStrategy":"validation","validationCode":"// Pre-validate before calling the downloader.\nif \"\" == pkgURL || \"\" == checksum {\n    return fmt.Errorf(\"cannot download: pkgURL or checksum empty\")\n}\nreturn downloadInstallPkg(pkgURL, checksum)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always source pkgURL and checksum from getUpdatePkg, which guarantees non-empties.","Treat an empty-argument hit as a bug to fix in the caller, not a runtime condition.","Add an assertion/unit test on every new call site."],"tags":["update","validation","precondition","download"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}